简单做个实验分析一下 new/new[] 和 delete/delete[]

先来介绍下流程。

  • new/new[],他的流程是先开辟了一个空间,然后调用了构造函数。
  • delete/delete[]先调用析构函数,然后释放内存。

那么如果new/deletenew[]/deletep[]没有配对会出现什么问题。
对于这个问题我做了简单的实验。

非基础类型

也就是自己写的类。
先说下结论

  • delete释放new[]只会调用第一个的析构函数,导致内存泄漏。
  • delete[]释放new会出bug

测试如下

class A{
    int a;
public:
    A():a(0xffff){
        cout<<"A()\n";
    }
    ~A(){
        cout<<"~A()\n";
    }
    virtual void func(){
        cout<<"func\n";
    }
};
int main() {
    A *b=new A[4];
    delete [] b;
    
    b =new A();
    delete b;
    
    b=new A[4];
    delete b;
    
    A *a=new A();
    delete[] a;
    return 0;
}

输出结果是

A()
A()
A()
A()
~A()
~A()
~A()
~A()//4个析构
A()
~A()//一个析构
A()
A()
A()
A()
~A()//一个析构
A()

Process finished with exit code -1073741819 (0xC0000005)//直接RE了

问题已经看出来,那么是为什呢。
我们去看看内存。
在这里插入图片描述
看到了吗,十分明显的一个数字,表示分配了多少个,后面很明显吧。一个虚函数指针,和一个值。
然后执行下一行释放内存。
在这里插入图片描述
看出内存的变化了吗,全部都释放掉了,前面那个4 也没了。
在这里插入图片描述
执行到这,用new创建的明显没有一个表示多少个的。
执行下一行
在这里插入图片描述
然后没了被释放了。

执行后面错误的。
看看用delele删除new[]
在这里插入图片描述

在这里插入图片描述
执行完后,他们全部都在,我都怀疑内存到底有没有释放。很显然全部都还没有释放掉。

然后后面那个为啥会RE不用我说了吧。
在这里插入图片描述
前面那个表述个数的数字这么大。。你想怎么搞。。。

小问题1不要慌

对于这个实验,如果把虚函数删掉,就不会是内存错误而是一个非常大的循环。至于为什么自己思考。

结论:

new参数的非基础类型,只会开辟一个对象内存空间,new[]还会保存一个数组大小。delete[]删除的时候会根据 删除地址前面的4个字节表示的数字大小来删除后面的对象。

为了保证正确性,我来做个有意思的事,我们来手写一个new[]

class A{
    int a;
public:
    A():a(0xffff){
        cout<<"A()\n";
    }
    ~A(){
        cout<<"~A()\n";
    }
    virtual void func(){
        cout<<"func\n";
    }
};
int main() {
    void *p=::operator new(sizeof(A)*4+sizeof(int));//这个可以用malloc来是一样的结果。
    int *size=(int *)p;
    *size=4;//这个设置一下大小
    A *a=(A *)(size+1);//这个就是new[] 的实现
    new(a)A();
    new(a+1)A();
    new(a+2)A();
    new(a+3)A();
    delete[] a;//显然这个是释放
    return 0;
}

理论上delete []也能手写实现,具体怎么实现读者自己动手操作,切忌拿来主义。

基本类型

对于基本类型和非基本类型有什么区别呢???,emmmm好像没啥区别。
但是他确实不一样。

int main() {
    int *b=new int[4]{0xfff,0xffff,0xfff,0xfff};
    delete [] b;

    b =new int();
    delete b;

    b=new int[4]{0xfff,0xffff,0xfff,0xfff};
    delete b;

    int *a=new int();
    delete[] a;
    return 0;
}

运行这个你会发现,没有任何问题!!!!,确实就是,没有任何问题。
为什么会这样???。
我们照着前面那个的来。
在这里插入图片描述
看到了吗,没有那个表示数组长度的东西了。
在这里插入图片描述
delete之后内存变了。

后面的自己看,你会发现,用delet删除new[]完全没问题。。。
delet[]删除new,好像也没啥问题。

那么问题来了,他们是怎么知道要释放多少内存的。
这个就比较复杂了。他和free是一个性质,内存分配是交给操作系统完成的,具体怎么操作的还是和内核有关。
应该也能很清楚的看见,每次释放内存,改变的不仅仅是你需要的的内存大小,而是一整块内存。
所以用delete/delete[]释放内存的时候,实际上是直接把那一块内存释放了。

结论:

对于基础类型,用delete/delete[]删除实际上是一样的,主要原因应该还是因为,他没有调用构造和析构的必要。如果一个类里面封装了一个指针,然后new了一个对象,如果不调用析构函数,就会出现内存泄漏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值