【深入理解C++】new/delete和new[]/delete[]探秘
创始人
2024-02-24 10:44:10
0

文章目录

  • 1.operator new()和operator delete()
  • 2.new记录分配的内存大小供delete使用
  • 3.new[]/delete[]申请和释放一个数组
    • 3.1 基本数据类型(内置类型)
    • 3.2 自定义类型(类类型)
  • 4.new/delete和new[]/delete[]要配对使用

1.operator new()和operator delete()

在这里插入图片描述

operator new() 和 operator delete() 是函数。

new 干了两个事情:

  1. 在堆中分配内存:通过 operator new() 来分配内存
  2. 调用构造函数来初始化内存

delete 也干了两个事:

  1. 调用析构函数
  2. 释放内存:调用 operator delete() 来释放内存

2.new记录分配的内存大小供delete使用

int *p = new int; // 4字节
delete p;

删除的时候,编译器怎么知道要回收的是 4 字节?

答:new 内部有记录机制,记录了分配出去多少内存。

new 如何记录分配的内存大小供 delete 使用?

答:不同的编译器,new 内部有不同的实现方式。

3.new[]/delete[]申请和释放一个数组

3.1 基本数据类型(内置类型)

举例1:

#include 
using namespace std;int main()
{int* p = new int(100); // 如果不释放,会泄漏4字节delete p;return 0;
}

举例2:

#include 
using namespace std;int main()
{int* p = new int[2]; // 如果不释放,会泄漏8字节delete[] p;return 0;
}

3.2 自定义类型(类类型)

举例1:

#include 
using namespace std;class A
{
public:A(){cout << "A::A()" << endl;}~A(){cout << "A::~A()" << endl;}
};int main()
{A* p = new A(); // 如果不释放,会泄漏1字节delete p;return 0;
}

在这里插入图片描述

举例2:

#include 
using namespace std;class A
{
public:A(){cout << "A::A()" << endl;}~A(){cout << "A::~A()" << endl;}
};int main()
{A* p = new A[2](); // 如果不释放,会泄漏6字节delete[] p;return 0;
}

在这里插入图片描述

疑问:为什么给类型 A 对象数组动态分配内存时多出来 4 个字节,而给内置类型 int 数组动态分配内存时并没有多出来 4 字节?

在上面的程序中,对于类类型 A,调用了两次构造函数、两次析构函数,也就是说,delete一个数组时,要为每一个数组元素调用析构函数。

但是,对于 delete 表达式,它并不知道数组的元素个数,只有 operator new() 函数和 operator delete() 函数知道。因此,必须有一种手段来告诉 delete 表达式的数组大小是多少。

那么,一种可行的方式就是,多分配一个大小为 4 字节的空间来记录数组大小,同时可以约定前 4 字节来记录大小。那么,由 operator new() 函数分配的地址与 new 表达式返回的地址应该相差 4 个字节。

当然,对于非类类型数组和不需要调用析构函数的类类型数组,这多余的 4 字节就不需要了。

4.new/delete和new[]/delete[]要配对使用

举例1:

#include 
using namespace std;int main()
{int* pi = new int[3]; // 如果不释放,会泄漏12字节//delete pi; // 这里即使用delete释放,也不会发生内存泄漏	delete[] pi; // 这种释放方法才是最规范的return 0;
}

举例2:

#include
using namespace std;class A
{
public:A(){cout << "A::A()" << endl;}// 没有自定义的析构函数
};int main()
{A* pa = new A[2](); // 如果不释放,会泄漏2字节//delete pa; // 这里即使用delete释放,也不会发生内存泄漏delete[] pa; // 这种释放方法才是最规范的return 0;
}

举例3:

#include 
using namespace std;class A
{
public:A(){cout << "A::A()" << endl;}~A(){cout << "A::~A()" << endl;}
};int main()
{A* pa = new A[2](); // 如果不释放,会泄漏6字节//delete pa; // 这里如果用delete释放,系统就会报告异常delete[] pa; // 这种释放方法才是最规范的return 0;
}

在这里插入图片描述

为什么自己一提供析构函数,不用 delete[] 来释放 new[] 出来的内存就报异常呢?

从上图中可以看出,只调用了 1 次 A 的析构函数而不是 2 次,表示肯定有内存泄漏。真正释放内存的是 operator delete() 函数,而多出来的 4 个字节导致释放内存空间错乱。

结论:如果一个对象(内置对象、类对象),使用 new[] 来分配内存,却用单独的 delete(而不是 delete[])来释放内存,那么这个对象需要满足的条件是:对象的类型要么是内置类型或者无自定义的析构函数的类类型。

相关内容

热门资讯

影院取消放映场,镇江消协调解:... 扬子晚报网12月20日讯(通讯员 陈红生 记者 万凌云 姜天圣)近日,消费者董女士投诉反映,在镇江一...
山西运城公安侦破两起燃气公司员... 又到一年取暖季,千家万户燃起天然气化作一股股暖流,守护着冬日里的烟火气。然而,在利益的驱使下,加之法...
120万的保时捷卡宴只卖60万... 12月18日,海南正式宣布封关,随着海南自贸港“零关税”进口车政策正式落地,很多网友发现,海南的进口...
海南封关,税收政策有哪些变化 12月18日,海南正式实施全岛封关。全岛封关运作是海南自贸港建设的标志性工程,是进一步扩大开放的重要...
六代刑侦人十八年追凶 犯罪嫌疑... 寇松 中青报·中青网记者 胡宁 初冬的深夜,首都机场公安局办公大楼前,20多个身影注视着大门的方向。...
关注增值税!2026年继续执行... 2026年执行的增值税优惠政策 基于行政行为的公定力、确定力、拘束力和执行力等四效力原则,税海涛声认...
辅警工作近6年因有纹身被辞退,... 红星新闻记者从一审判决书中看到,原告刘某在诉讼中称,自己于2019年9月入职被告单位,任警务辅助人员...
法院回应女子家门口遇害案量刑问... 12月20日,成都市中级人民法院一审公开宣判被告人梁某滢故意杀人一案,对被告人梁某滢以故意杀人罪判处...
枣庄程晓庆首饰店,其实是犯罪窝... 一家不营业的商铺,每日资金流水不断,这背后,可能藏着不可告人的秘密。近日,在枣庄市公安局刑侦支队的指...
众泰汽车拟与上汽变速器公司达成... 瑞财经 刘治颖 12月18日,众泰汽车(SZ000980)公告,就公司全资子公司浙江深康汽车车身模具...