虚拟分割器​​故障

时间:2011-09-25 18:16:04

标签: c++ destructor

我在C ++中有以下代码:

#include <iostream> 

class Number 
{ 
public: 
    virtual void foo(){std::cout << "Number foo\n";};
    Number (){ std::cout << "Number ctor" << std::endl;} 
    virtual ~Number(){ std::cout << "Number dtor" << std::endl;} 
}; 


class Complex : public Number 
{ 
public:
    virtual void foo(){std::cout << "Complex foo\n";};
    Complex (double r=0, double i=0) : _r (r), _i (i)
    { std::cout << "Complex ctor" << std::endl; };
    virtual ~Complex(){ std::cout << "Complex dtor" << std::endl;}
private: 
    double _r,_i;
};


int main()
{
    Number *numArr = new Complex [2];
    delete [] numArr;
    return 0; 
}

当析构函数声明为虚拟时,应用程序将退出并出现分段错误。当它没有被声明为虚拟时,会调用Number类析构函数(这很明显......)。但是,当析构函数被声明为虚拟时,当我删除Complex类中的双精度时,没有分段错误,并且析构函数按预期顺序(Complex,Number)调用,所以我猜问题是相关的对于物体的大小,有人可以给我一个解释吗? 谢谢, 阿米特。

3 个答案:

答案 0 :(得分:6)

Number *numArr = new Complex [2];
delete [] numArr;

实际上,删除操作会调用未定义的行为。

§5.3.5/ 3说,

  

在第一个备选(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数的动态类型的基类,静态类型应具有虚拟析构函数或者行为未定义。 在第二种方法(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义。

它的实际含义是:

Number *object= new Complex();
delete object; //well-defined

//BUT
Number *array = new Complex[N];
delete [] array; //undefined

答案 1 :(得分:4)

你不能在C ++中拥有多态数组。数组依赖于指针算法,指针算法依赖于编译器知道对象大小。在您的情况下,对超出第0个数组的任何元素的任何访问都是未定义的。

答案 2 :(得分:2)

我不完全确定,但这是我怀疑的......

我想知道这是否与一个派生类数组不应该被转换为基类数组这一事实有关(它们不相同,请参阅:http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.3):如何{{1知道它正在删除的对象的大小,调整deletenumArr[0]的指针(找到v-table并将numArr[1]传递给d-tor)

显然,标准明确地将其命名为undefined(5.3.5):

  

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