【问题标题】:Virtual dtor segmentation fault虚拟 dtor 分段错误
【发布时间】:2011-09-25 18:16:03
【问题描述】:

我在 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 类中的双精度时,没有分段错误并且析构函数按预期的顺序(复杂,数字)调用,所以我猜这个问题是相关的到对象的大小,谁能给我一个解释? 谢谢, 阿米特。

【问题讨论】:

  • @AndersK。这应该到处都失败。
  • 代码表现出未定义的行为,问题是重复的:stackoverflow.com/questions/7197677/…
  • 我似乎每天都在学习新东西。仍然。
  • 当然还有boost::ptr_vector&lt;Number&gt;std::vector&lt;std::unique_ptr&lt;Number&gt;&gt;等...

标签: c++ destructor


【解决方案1】:
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

【讨论】:

    【解决方案2】:

    C++ 中不能有多态数组。数组依赖于指针算术,而指针算术依赖于编译器知道对象大小。在您的情况下,对数组中第零以外的任何元素的任何访问都是未定义的。

    【讨论】:

    • 我最喜欢这个解释。我不太明白其他答案,但这个答案让我说“明白了!”
    【解决方案3】:

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

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

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

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

    【讨论】:

    • Nawaz 在相关标准引用方面击败了我。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-22
    • 2020-07-04
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多