删除一个对象数组,该数组被上推为基指针

Deleting an array of objects upcasted to base pointers

本文关键字:数组 上推 指针 一个对象 删除      更新时间:2023-10-16

开始将一些库从msvc移到mingw,并且发现当想要删除一个数组的更新对象时,msvc的行为非常有趣。也就是说,msvc做了一些黑魔法(它似乎喜欢这样做),下面的代码执行得很好,但是在mingw(4.7.2)(崩溃)。我相信mingw的运行是正确的,这是msvc的巫术,这是产生潜伏bug的问题。

代码:

#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) 

我的问题是,解决这个问题的正确方法是什么?目前我想到的修补方法只是尝试向下转换到每个可能的类,并在向下转换的指针上调用delete操作:

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

除了重新设计库(不是我的),有没有更好的方法?

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

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

所以,在这种情况下,你不应该依赖于Visual c++的温和行为,而应该尝试为数组delete操作符提供正确类型的指针,这基本上意味着在你的情况下动态转换。

您可以通过使用vector实例来存储逐个分配的上映射对象来避免这个问题。

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];