栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

基类指针delete派生类数组(VC++实现原理)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基类指针delete派生类数组(VC++实现原理)

class A
{
public:
	A() {
	}
    //default A::destructor
private:
    ...
    //members
};

class B : public A
{
public:
	B(){}
    //default B::destructor
private:
    ...
    //members
};

有如上类定义A B,则delete A指针接收的B数组行为是未定义的:

	A* a = new B[2];
	delete [] a;

The C++ Standard, [expr.delete], paragraph 3 [ISO/IEC 14882-2014], states the following:

In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.

 原因是此行为会被扩展为如下形式:

//C++数组中的元素逆序销毁(C++ Primer p425)
for(int i = len - 1; i >= 0; --i){
    A* pa = array + i * length(A);
    call pa->~A();
}

call A::operator delete[]

可见,指针的偏移是由A类型(静态类型)的长度计算得出,所以析构时会出现错误。VC++环境下会出现crash。

但实践中如果给A声明虚析构函数,并声明B的析构函数,则在VC++编译环境下不会出现crash,这是为什么呢?

查看汇编代码得知,当编译器检测到虚析构函数被重载(仅有虚析构还不行,必须有派生类重载)的情况下,会给基类产生一个虚函数vector deleteing destructor,派生类会重载这个虚函数:

class A
{
public:
	A() {
	}
    virtual ~A(){}
public:
    virtual vector deleting destructor(...);

private:
    ...
    //members
};

class B : public A
{
public:
	B(){}
    ~B()override{}

public:
    vector deleting destructor(...)override;

private:
    ...
    //members
};

此函数的作用是实现正确的类型数组的析构操作,也就是对应B类型来说,可以生成如下代码:

void vector deleting destructor(...){
    for(int i = len - 1; i >= 0; --i){
        B* pb = array + i * length(B);
        call pb->~B();
    }
}

 这样可以正确的计算偏移以析构每一个对象。

此情景下的的B类型虚表:

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/743526.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号