当前位置: 首页 > news >正文

Item16--`new` 与 `delete` 的对应规则

👨‍🏫 条款 16 详解:newdelete 的对应规则

1. 核心规则回顾

分配 (new) 释放 (delete) 语义
new T delete p 分配/释放单个对象
new T[ ] delete [ ] p 分配/释放对象数组

违反这条规则会导致未定义行为 (Undefined Behavior, UB)。 在 C++ 中,未定义行为意味着程序的行为是不可预测的,可能表现为内存泄漏、数据损坏或程序崩溃。

2. 深入探究:为什么会出错?

当涉及拥有析构函数的类类型对象时,形式不匹配的问题最为严重。

A. 错误一:new T[] 配上 delete p

// 假设 ResourceHolder 是一个拥有析构函数的类
ResourceHolder* pArray = new ResourceHolder[5];
// ...
delete pArray; // 错误: new[] 却用了 delete

🔍 原理分析:

  1. new ResourceHolder[5] 的操作: 编译器在分配内存时,通常会在实际对象数组之前(或之后)预留一块空间,用于存储数组的元素个数(即 5)。接着,它会循环调用 5 次 ResourceHolder构造函数
  2. delete pArray 的操作: 运行时看到没有方括号的 delete,它假设这是单个对象的释放。它执行以下操作:
    • 只调用一次 ResourceHolder析构函数(针对数组的第一个元素 pArray[0])。
    • 释放整个内存块。

⚠️ 后果:

  • 资源泄漏: pArray[1]pArray[4] 这 4 个对象的析构函数没有被调用。如果这些对象在析构函数中释放了资源(如文件句柄、网络连接或内部堆内存),这些资源将无法被释放,造成典型的资源泄漏

B. 错误二:new T 配上 delete[] p

ResourceHolder* pSingle = new ResourceHolder;
// ...
delete [] pSingle; // 错误: new 却用了 delete[]

🔍 原理分析:

  1. new ResourceHolder 的操作: 仅为单个对象分配内存,并调用一次构造函数。内存块中没有存储数组大小的额外信息。
  2. delete [] pSingle 的操作: 运行时看到带方括号的 delete[],它会去寻找存储在内存块开头的数组大小信息。由于没有这个信息,它会读取该内存位置上的垃圾数据,并将其误认为是数组大小。

⚠️ 后果:

  • 程序崩溃: 运行时可能会基于这个错误的“大小”多次调用析构函数,这不仅是不必要的,而且极有可能访问到不属于该对象的内存,导致堆损坏程序立即崩溃

3. 解决方案:使用智能指针

条款 16 是 C++ 内存管理中一个常见的错误源。为了彻底避免这类问题,最好的办法是不要自己管理内存

推荐做法:使用 std::unique_ptr 管理动态分配的内存。

自 C++11 起,std::unique_ptr 被设计成能安全地处理单个对象和数组:

场景 代码 自动释放
单个对象 auto p = std::make_unique<T>(); p 超出作用域时,自动调用 delete p.release()
对象数组 auto p = std::make_unique<T[]>(N); p 超出作用域时,自动调用 delete [] p.release()
// 推荐示例:
#include <memory>// 单个对象
auto p1 = std::make_unique<ResourceHolder>(); 
// p1 离开作用域时,自动调用 delete// 对象数组 (N=5)
auto p2 = std::make_unique<ResourceHolder[]>(5);
// p2 离开作用域时,自动调用 delete[] (且会调用所有5个析构函数)

使用 std::unique_ptr 不仅保证了异常安全(即使发生异常也会释放资源),还自动选择了正确的 delete 形式,完全消除了条款 16 中描述的风险。

http://www.jsqmd.com/news/115959/

相关文章:

  • 3777. 使子字符串变交替的最少删除次数
  • item11--在 operator= 中处理“自我赋值
  • 预见2026:家居新品首秀平台选择战略——五大核心展会深度评估与推荐 - 匠子网络
  • Item20--宁以 pass-by-reference-to-const 替换 pass-by-value
  • 研究生必备!8个免费AI论文工具,半天生成5000字问卷论文还有高信度数据
  • Item20--宁以 pass-by-reference-to-const 替换 pass-by-value
  • Item17--以独立语句将 `new` 到的对象置入智能指针
  • Item17--以独立语句将 `new` 到的对象置入智能指针
  • 3433. 统计用户被提及情况
  • Item19--设计 class 犹如设计 type
  • 国外软件,安装即时专业版!
  • Item19--设计 class 犹如设计 type
  • basic_regex
  • c++狼人杀
  • 宠物识别丨基于弱监督学习的宠物视频内容自动标注技术实践 - 指南
  • 朴易天下:道家修行的专业术语分享
  • 个人投资者的落地路径:从“说人话,做量化”到实盘前的三道关
  • 神经网络中的 block 和 module
  • item13--使用对象管理资源
  • 深入解析:蓝桥杯基础算法精讲:模拟与高精度运算实战指南
  • item12-- 拷贝一个对象的所有组成部分
  • sub_match
  • sub_match
  • 抽奖机随机号码生成:3 种算法实现 + 测试全解析(附完整代码)
  • 【零基础精通】Python 字符串全解析:从字符序列到不可变对象的深度构建
  • item14--谨慎考虑资源管理类的拷贝行为
  • python django flask酒店客房管理系统数据可视化分析系统_gq8885n3--论文md5
  • python django flask鹿幸公司员工食堂在线点餐餐饮餐桌预约管理系统的设计与实现_utcnqqs0--论文
  • error_code
  • 虚拟化初步了解