Item16:成对使用new和delete时要采取相同形式
在C++中,new
与delete
是管理动态内存的核心操作符,但它们的使用存在严格的“配对规则”。《Effective C++》Item16“成对使用new和delete时要采取相同形式”(Use the same form in corresponding uses of new and delete)明确指出:用new
分配内存时,必须用对应的delete
形式释放——单个对象用delete
,数组用delete[]
。违反这一规则会导致未定义行为,轻则内存泄露,重则程序崩溃。本文将深入解析这一条款,探讨配对规则的底层逻辑、不匹配的风险及实践中的注意事项。
一、new与delete的底层工作机制
要理解配对规则,需先明确new
和delete
的工作流程:
(一)单个对象的分配与释放(new
+ delete
)
-
new T
的操作:- 调用
operator new
分配足够存储T
类型对象的内存; - 在分配的内存上调用
T
的构造函数,初始化对象。
- 调用
-
delete p
的操作:- 调用
p
指向对象的析构函数,清理资源; - 调用
operator delete
释放内存。
- 调用
(二)数组的分配与释放(new[]
+ delete[]
)
-
new T[n]
的操作:- 调用
operator new[]
分配内存(除了存储n
个T
对象,通常还会额外分配4/8字节存储数组大小n
); - 依次在内存上调用
n
次T
的构造函数,初始化每个元素。
- 调用
-
delete[] p
的操作:- 根据额外存储的数组大小
n
,依次调用n
次T
的析构函数; - 调用
operator delete[]
释放整个数组的内存。
- 根据额外存储的数组大小
核心差异:数组的“大小记录”
new[]
会在内存块头部隐式存储数组元素数量(n
),这是delete[]
能够正确调用所有元素析构函数的关键。而new
(单个对象)不会存储额外信息,delete
也无需处理数组逻辑。
二、不匹配的风险:未定义行为的根源
若new
与delete
形式不匹配(如用delete
释放new[]
分配的数组,或用delete[]
释放new
分配的单个对象),会导致底层机制混乱,引发未定义行为。
(一)用delete
释放new[]
分配的数组(最危险)
假设我们分配一个对象数组: