4

开始将一些库从 msvc 移动到 mingw,当人们想要删除一向上转换的对象时,发现 msvc 的行为非常有趣。即 msvc 做了一些黑魔法(它似乎喜欢这样做),并且下面的代码执行得很好,但是在 mingw(4.7.2(崩溃。我相信 mingw 执行正确,它的 msvc voodoo 就是制作一个问题卧铺虫。

代码:

#include <iostream>

class foo{
    static int idgen;
protected:
    int id;
public:
    foo(){
        id = idgen++;
        std::cout << "Hello  ( foo - "<<id<<")"<<std::endl;
    }
    virtual ~foo(){
        std::cout << "Bye bye ( foo - "<<id<<")"<<std::endl;
    };
};

int foo::idgen = 0;


class bar: public foo{
    double some_data[20];
public:
    bar(){

    std::cout << "Hello  ( bar - "<<id<<")"<<std::endl;
}
    ~bar(){
        std::cout << "Bye bye ( bar - "<<id<<")"<<std::endl;
    }
};

int main()
{
    const unsigned int size = 2;
    foo** arr = new foo*[size];
    {
        bar* tmp = new bar[size];
        for(int i=0; i<size; i++)
        {
            arr[i] = &(tmp[i]); //take address of each object
        }
    }

    delete [] arr[0]; //take address of first object, pointer is same as tmp. This also crashes mingw
    delete [] arr;

}

msvc 2010 的输出

Hello  ( foo - 0)
Hello  ( bar - 0)
Hello  ( foo - 1)
Hello  ( bar - 1)
Bye bye ( bar - 1)
Bye bye ( foo - 1)
Bye bye ( bar - 0)
Bye bye ( foo - 0)

还有 mingw (在毁灭中坠毁)

Hello  ( foo - 0)
Hello  ( bar - 0)
Hello  ( foo - 1)
Hello  ( bar - 1) 

我的问题是,解决此问题的正确方法是什么。我想出的当前 hackfix 仅涉及尝试向下转换到每个可能的类并在向下转换的指针上调用删除操作:

if(dynamic_cast<bar*>(arr[0]) != 0)
    delete [] dynamic_cast<bar*>(arr[0]); 

除了重新设计库(它不是我的)之外,还有更好的方法吗?

4

2 回答 2

4

在标准规范第 5.3.5 节第 3 段中,关于delete操作员:

[...] 在第二种选择(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义。

因此,确实,在这种情况下,您不应该依赖 Visual C++ 的温和行为,并尝试为数组delete运算符提供正确类型的指针,这基本上意味着在您的情况下进行动态转换。

您可以通过使用向量实例来存储一个一个分配的向上转换的对象来避免这个问题。

于 2013-05-15T23:30:52.297 回答
1

gcc 4.7.2 即使在这里有一个简单的例子也会失败 -> ideone.com/z876QX#view_edit_box 所以如果它是一个数组,我们显然不能使用虚拟析构函数。

const unsigned int size = 2;
foo* test = new bar[size];
delete[] test;

但是,如果您使用允许您使用delete而不是delete[].

http://ideone.com/NfbF3n#view_edit_box

const int size = 5;
foo *test[size];
for(int i = 0; i < size; ++i)
    test[i] = new bar;
for(int i = 0; i < size; ++i)
   delete test[i];
于 2013-05-15T23:38:03.400 回答