xml*_*lmx 16 c++ polymorphism virtual standards destructor
#include <iostream>
using namespace std;
struct Base
{
    virtual ~Base()
    {
        cout << "~Base(): " << b << endl;
    }
    int b = 1;
};
struct Derived : Base
{
    ~Derived() override
    {
        cout << "~Derived(): " << d << endl;
    }
    int d = 2;
};
int main()
{
    Base* p = new Derived[4];
    delete[] p;
}
输出如下:(带有Clang 3.8的Visual Studio 2015)
~Base(): 1
~Base(): 2
~Base(): -2071674928
~Base(): 1
为什么多态不适用于C++中的数组?
R S*_*ahu 20
鉴于,
Base* p = Derived[4];
C++ 11标准制作
delete [] p;
是未定义的行为.
5.3.5删除
...
2 ...在第二个备选(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义.
从内存布局的角度来看,为什么delete [] p;会导致未定义的行为也是有道理的.
如果sizeof(Derived)是N,new Derived[4]分配内存将是这样的:
+--------+--------+--------+--------+
|   N    |   N    |   N    |   N    |
+--------+--------+--------+--------+
一般来说,sizeof(Base)<= sizeof(Derived).在您的情况下,sizeof(Base)< sizeof(Derived)since Derived有一个额外的成员变量.
当你使用:
Base* p = new Derived[4];
你有:
p
|
V
+--------+--------+--------+--------+
|   N    |   N    |   N    |   N    |
+--------+--------+--------+--------+
p+1指向第一个对象中间的某个位置sizeof(Base) < sizeof(Derived).
       p+1
       |
       V
+--------+--------+--------+--------+
|   N    |   N    |   N    |   N    |
+--------+--------+--------+--------+
当调用析构函数时p+1,指针不指向对象的开头.因此,该程序表现出不确定行为的症状.
相关问题
由于尺寸的差异Base和Derived,你不能遍历使用动态分配的数组中的元素p.
for ( int i = 0; i < 4; ++i )
{
   // Do something with p[i]
   // will not work since p+i does not necessary point to an object
   // boundary.
}
das*_*ght 14
您得到未定义的行为,因为操作员delete[]不知道数组中存储了什么类型的对象,因此它信任静态类型来决定单个对象的偏移量.标准说明如下:
在第二个备选(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义.
数组的静态类型需要匹配用于分配的元素类型:
Derived* p = new Derived[4]; // Obviously, this works
本问答详细介绍了该标准有此要求的原因.
至于修复此行为,您需要创建一个指针数组,常规或智能(最好是智能以简化内存管理).