深度探索new和delete

来源:互联网 发布:linux如何挂载磁盘 编辑:程序博客网 时间:2024/06/05 23:03
#include <stdio.h>#include <iostream>using namespace std;class A{public:    virtual    ~A()    {        cout << "in A" << endl;    }    int a;};class B : public A{public:    ~B()    {        cout << "in B" << endl;    }    int b;};int main(int argc,char **argv, char**env){    while(*env)    {        //puts(*env);        env++;    }    A *p = new B[1];    delete [] p;    return 0;}
ⅠA *p = new B;delete p;in AⅡvirtualA *p = new B;delete p;in Bin AⅢA *p = new A[2];delete p;in AⅣA *p = new A[2];delete [] p;in Ain AⅤvirtualA *p = new B[2];delete [] p;如果sizeof(B)==sizeof(A)in Bin Ain Bin A如果sizeof(B)>sizeof(A)执行异常ⅥA *p = new B[2];delete [] p;in Ain A

Ⅰ~Ⅳ比较好理解,不再说明.

new B[2];开辟了一块内存,大小为2*sizeof(B),并对每个B都执行了构造函数,然后返回该内存块的起始地址.delete p;先对p指向的内存调用**p指向类型**的析构函数(如果p指向的类型的析构是virtual的,则会通过vptr调用派生类的析构函数,这是编译器在编译时扩充的操作),再free掉该内存块.delete [] p;对于new[],(比较可能)编译器会维护一个map,放置指针及数组元素的个数;执行delete [] p;时,会找到p对应的数组元素的个数,然后对p指向的内存块,依次调用**p指向类型**的析构函数(以sizeof(*p)为跃度).在Ⅴ第一种情况和Ⅵ中,并不涉及数据成员的操作,而且析构函数也没有使用class B的数据成员,所以没有问题;但是Ⅴ的第二种情况,由于析构函数是virtual的,会调用p->vptr[0]指向的析构函数,这倒也不打紧,但当为第二个数组元素执行析构的时候,(p+sizeof(A))->vptr[0]就有问题了,本应是(p+sizeof(B))->vptr[0]才对,取错误的vptr,自然造成了运行时错误.所以,下面的代码就不会出现运行时错误:virtualA *p = new B[1];delete [] p;


A (*p)[3] = new A[2][3];
delete p;和delete [] p;均可以成功调用6次析构函数
大概编译器检测到p的类型是A(*)[],自动做了一些操作


写编译器的人真nb
参考:《深度探索C++对象模型》6.2节

0 0