运算符delete[]中的分段错误

Max*_*del 15 c++ destructor delete-operator

我在下一个代码中遇到分段错误异常:

class A {
public:
    A() {}
    virtual ~A(){}
    double m_d;
};
class B : public A {
public:
    B() {}
    virtual ~B(){}
    int x;
};
int main()
{
    A* ptr = new B[5];
    delete[] ptr;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果删除d'tors,也不例外。预计不会收到异常。

编译器:g++(Ubuntu 11.2.0-19ubuntu1)11.2.0

Hol*_*Cat 13

数组delete不尊重虚拟析构函数。尝试将基类指针传递给它会导致未定义的行为。

[expr.delete]/2

...在单对象删除表达式中, 的操作数的值delete可以是空指针值、由先前的非数组 new 表达式产生的指针值或指向对象的基类子对象的指针由这样一个新的表达方式创造出来。如果不是,则行为未定义。在数组删除表达式中, 的操作数的值delete可以是空指针值或由先前数组 new 表达式产生的指针值。如果不是,则行为未定义。

请注意第二个列表不包括“基类子对象...”部分。

[expr.delete]/3

...在数组删除表达式中,如果要删除的对象的动态类型与其静态类型不相似,则行为未定义。

其中“静态类型”是在编译时确定的类型,“动态类型”是在运行时确定的最派生对象的类型,“相似”或多或少意味着“相同的类型”,但允许一些差异常量等等。

  • 其未定义的行为方面怎么强调都不为过。我编译并运行了 OP 的代码,没有出现段错误,这可能很容易被误认为该代码可以安全地按预期工作。 (6认同)

小智 7

这是不允许的,如下所述: Why is it undefined behavior to delete[] an array of returnedobjects via a basepointer?

摘录:C++03 标准5.3.5 [expr.delete] p3在第二种选择(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义

出于好奇,我还制作了日志版本:

#include <iostream> 

class A {
public:
    A() {}
    virtual ~A(){ std::cout << m_d << " ; ";}
    double m_d {0.5};
};
class B : public A {
public:
    B() {}
    virtual ~B(){ std::cout << x << " : "; }
    int x {2};
};
int main()
{
    A* ptr = new B[5];
    delete[] ptr;
    std::cout << "Hi, nothing crashed here!\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/Y7xGdKd3f

Clang:使用不正确的数据调用基类析构函数

2.07634e-317 ; 0.5 ; 9.88131e-324 ; 2.07634e-317 ; 0.5 ; Hi, nothing crashed here!

Gnu:礼貌地崩溃

Program returned: 139

M$:按预期工作:)

2 : 0.5 ; 2 : 0.5 ; 2 : 0.5 ; 2 : 0.5 ; 2 : 0.5 ; Hi, nothing crashed here