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;
}
Run Code Online (Sandbox Code Playgroud)
输出如下:(带有Clang 3.8的Visual Studio 2015)
~Base(): 1
~Base(): 2
~Base(): -2071674928
~Base(): 1
Run Code Online (Sandbox Code Playgroud)
为什么多态不适用于C++中的数组?
R S*_*ahu 20
鉴于,
Base* p = Derived[4];
Run Code Online (Sandbox Code Playgroud)
C++ 11标准制作
delete [] p;
Run Code Online (Sandbox Code Playgroud)
是未定义的行为.
5.3.5删除
...
2 ...在第二个备选(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义.
从内存布局的角度来看,为什么delete [] p;会导致未定义的行为也是有道理的.
如果sizeof(Derived)是N,new Derived[4]分配内存将是这样的:
+--------+--------+--------+--------+
| N | N | N | N |
+--------+--------+--------+--------+
Run Code Online (Sandbox Code Playgroud)
一般来说,sizeof(Base)<= sizeof(Derived).在您的情况下,sizeof(Base)< sizeof(Derived)since Derived有一个额外的成员变量.
当你使用:
Base* p = new Derived[4];
Run Code Online (Sandbox Code Playgroud)
你有:
p
|
V
+--------+--------+--------+--------+
| N | N | N | N |
+--------+--------+--------+--------+
Run Code Online (Sandbox Code Playgroud)
p+1指向第一个对象中间的某个位置sizeof(Base) < sizeof(Derived).
p+1
|
V
+--------+--------+--------+--------+
| N | N | N | N |
+--------+--------+--------+--------+
Run Code Online (Sandbox Code Playgroud)
当调用析构函数时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.
}
Run Code Online (Sandbox Code Playgroud)
das*_*ght 14
您得到未定义的行为,因为操作员delete[]不知道数组中存储了什么类型的对象,因此它信任静态类型来决定单个对象的偏移量.标准说明如下:
在第二个备选(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义.
数组的静态类型需要匹配用于分配的元素类型:
Derived* p = new Derived[4]; // Obviously, this works
Run Code Online (Sandbox Code Playgroud)
本问答详细介绍了该标准有此要求的原因.
至于修复此行为,您需要创建一个指针数组,常规或智能(最好是智能以简化内存管理).