我开始将一些库从msvc移植到mingw,在删除向上转型的对象数组时,发现了msvc非常有趣的行为。换言之,msvc进行了一些黑魔法(似乎喜欢这样做),下面的代码在msvc中可以正常执行,但在mingw(4.7.2)中会崩溃。我认为mingw表现正确,问题在于msvc使用了某种死板的代码导致了难以察觉的错误。
代码:
#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]);
除了重新设计库(它不是我的),还有更好的方法吗?
&(tmp[0])
返回与tmp
相同的值,因此当您调用delete[] arr [0]
时,您一次性删除整个tmp
数组。 - Sergey Kalinichenkoarr[i] = &(tmp[i]);
替换为arr[i] = (!i) ? tmp : &(tmp[i]);
,看看是否会有任何变化(尽管我怀疑会不会有变化)... - Sergey Kalinichenkoarr[i] = &(tmp[i]);
和arr[i] = (!i) ? tmp : &(tmp[i]);
是等价的,因为它们取相同的地址。我怀疑问题出在new[]
和delete[]
所使用的元数据上,因为标准中没有对此进行定义,导致了这种依赖实现的边界情况。对我来说,最大的问题是,哪种行为是正确的,或者删除向上转型的对象数组是否是未定义的操作? - Honf