Effective C++ 条款16: 成对使用new和delete时要采用相同形式
Effective C++ 条款16:成对使用new和delete时要采用相同形式
核心思想:动态分配数组时使用new[]
和delete[]
,分配单个对象时使用new
和delete
,两者必须严格匹配,否则导致未定义行为(内存泄漏或程序崩溃)。
⚠️ 1. 混用形式的灾难性后果
错误配对示例:
// 场景1:数组分配用delete释放
std::string* strArray = new std::string[10];
delete strArray; // 错误!应为delete[] → 内存泄漏/程序崩溃// 场景2:单个对象用delete[]释放
std::string* singleStr = new std::string;
delete[] singleStr; // 错误!应为delete → 程序崩溃
内存布局差异:
分配方式 | 内存布局 | 释放所需操作 |
---|---|---|
new | [对象数据] | 调用1次析构函数 |
new[] | [数组长度][对象1][对象2]… | 调用n次析构函数+长度读取 |
🚨 2. 解决方案:严格配对使用
正确配对规则:
// 单个对象
Type* singleObj = new Type; // 分配
delete singleObj; // 释放// 对象数组
Type* objArray = new Type[10]; // 分配
delete[] objArray; // 释放
typedef陷阱与修复:
// 危险:隐藏数组类型
typedef std::string AddressLines[4];
std::string* pal = new AddressLines; // 实际是new string[4]delete pal; // 错误!未使用delete[] → 仅析构第一个元素
delete[] pal; // 正确!严格匹配new[]
⚖️ 3. 关键原则与注意事项
原则 | 说明 | 违反后果 |
---|---|---|
new/delete配对 | 单个对象分配释放必须成对使用 | 对象析构不全 |
new[]/delete[]配对 | 数组分配释放必须成对使用 | 内存泄漏或程序崩溃 |
避免typedef数组 | 使用std::vector 或std::array 替代数组typedef | 消除配对认知负担 |
智能指针优先 | 使用std::vector /unique_ptr<T[]> 管理数组 | 自动匹配释放形式 |
现代C++最佳实践:
// 替代原生数组(推荐)
std::vector<std::string> addressLines(4); // 自动管理内存// 需要裸指针时使用智能指针数组版本
auto pal = std::make_unique<std::string[]>(4); // C++14+
pal[0] = "1600 Pennsylvania Ave";
// 自动调用delete[]释放
类型安全封装:
template<typename T>
using ArrayPtr = std::unique_ptr<T[]>; // 安全数组指针别名ArrayPtr<std::string> createAddress() {return std::make_unique<std::string[]>(4);
} // 自动正确释放
💡 关键原则总结
- 严格配对原则
new
→delete
new Type[n]
→delete[]
- 绝对禁止交叉使用
- typedef数组的危险性
- 避免对数组类型使用typedef → 改用
std::vector
或std::array
- 必须typedef时显式标注
delete[]
- 避免对数组类型使用typedef → 改用
- 智能指针自动匹配
std::unique_ptr<T[]>
自动使用delete[]
std::shared_ptr
需自定义数组删除器
错误示例诊断:typedef导致的隐性错误
typedef int BufferType[1024]; int* buffer = new BufferType; // 实际分配数组delete buffer; // 错误!应为delete[] → 仅释放第一个元素
安全修复方案:
// 方案1:显式使用delete[] delete[] buffer; // 正确配对// 方案2:改用标准容器(推荐) std::array<int, 1024> buffer; // 栈分配自动管理// 方案3:智能指针管理 auto buffer = std::make_unique<int[]>(1024);