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

C++中new和delete的多重面孔:operator new、new operator与placement new解析

《More Effective C++:35个改善编程与设计的有效方法》
读书笔记:了解各种不同意义的new和delete
在这里插入图片描述

在C++的内存管理体系中,newdelete看似简单,实则隐藏着多层逻辑。许多开发者对 new operatoroperator newplacement new 的区别感到困惑。本文将逐层拆解这些概念,帮你掌握内存分配与对象构造的底层逻辑。

一、new operator:语言内置的“双任务”操作符

我们日常写的 new Type(...) 其实是 new operator(新表达式),它的行为由语言内置,不可直接修改。其核心工作分为两步:

  1. 分配内存:调用 operator new 函数,申请足够容纳 Type 对象的内存;
  2. 构造对象:调用 Type 的构造函数,初始化刚分配的内存。

示例

string* ps = new string("Memory Management");

编译器会隐式生成类似以下逻辑:

// 1. 分配内存(调用 operator new)
void* raw_memory = operator new(sizeof(string));  
// 2. 构造对象(编译器通过 placement new 实现)
string* ps = new (raw_memory) string("Memory Management");  

二、operator new:可重载的内存分配函数

operator new普通函数,负责纯粹的内存分配,不涉及构造函数。它的原型为:

void* operator new(size_t size);
关键特性:
  • 可定制性:可全局或类内重载,实现自定义内存分配策略(如内存池、统计分配次数);
  • 直接调用:仅分配内存,返回未初始化的 void*,需后续手动构造对象。

示例

// 仅分配内存,无构造函数调用
void* raw_memory = operator new(sizeof(string));  

三、placement new:在指定内存上构造对象

placement new 是 operator new 的特殊重载版本,允许在已有的内存地址上构造对象,跳过“分配内存”步骤。

核心逻辑:
  • 原型(标准库实现):
    void* operator new(size_t, void* location) {  return location; // 直接返回传入的内存地址,不分配新内存  
    }  
    
  • 使用场景
    • 内存池:预先分配大块内存,后续在其上构造对象(减少分配开销);
    • 共享内存/内存映射IO:对象必须位于特定地址。
使用步骤:
  1. 准备原始内存:可以是栈内存、共享内存等(需保证内存大小和对齐正确);
  2. 调用 placement new 构造对象
  3. 手动调用析构函数(因 delete 会调用 operator delete,而此处内存可能非 operator new 分配,故不能直接 delete);
  4. 释放原始内存(若内存是动态分配的)。

示例

class Widget {  
public:  Widget(int size) {}  ~Widget() {}  
};  // 步骤1:准备栈内存(也可是共享内存等)  
alignas(Widget) char buffer[sizeof(Widget)];  // 步骤2:在 buffer 上构造 Widget  
Widget* pw = new (buffer) Widget(10);  // 步骤3:手动析构(必须!否则析构函数不会被调用)  
pw->~Widget();  // 步骤4:若 buffer 是动态分配,需释放(此处栈内存自动释放,故省略)  

注意:使用 placement new 需包含头文件 <new>

四、delete的对称逻辑:delete operator与operator delete

delete 操作符(delete operator)与 new 对称,也分两步:

  1. 析构对象:调用对象的析构函数;
  2. 释放内存:调用 operator delete 函数释放内存。
示例:
delete ps;  

编译器隐式生成:

ps->~string(); // 析构对象  
operator delete(ps); // 释放内存  
特殊情况:placement new构造的对象

若对象由 placement new 构造(内存非 operator new 分配,如栈内存、共享内存),不能直接用 delete,否则 operator delete 会错误释放内存。正确流程:

// 假设 pw 构造在共享内存上  
pw->~Widget(); // 手动析构  
freeShared(pw); // 释放共享内存(而非 operator delete)  

五、数组的处理:new[]与delete[]

当用 new Type[size] 分配数组时,实际调用的是 数组版 new operator,流程为:

  1. 调用 operator new[] 分配内存(可重载);
  2. 为数组每个元素调用默认构造函数(若 Type 有默认构造函数)。

对应的 delete[] 会:

  1. 为数组每个元素调用析构函数
  2. 调用 operator delete[] 释放内存(可重载)。
关键注意:
  • 配对使用new[] 必须与 delete[] 配对,否则可能漏调析构函数(如用 delete 代替 delete[],仅调用第一个元素的析构);
  • 旧编译器兼容operator new[] 支持较晚,旧编译器可能 fallback 到全局 operator new,导致数组内存分配难以定制。

总结:概念地图

概念角色核心行为可定制性
new operator语言操作符分配内存(调用 operator new) + 构造对象(placement new 隐式调用)不可直接定制
operator new内存分配函数仅分配内存,返回 void*可重载(全局/类)
placement newoperator new 的重载版本在指定内存地址上构造对象(通过额外参数指定地址)可自定义重载
delete operator语言操作符析构对象 + 释放内存(调用 operator delete)不可直接定制
operator delete内存释放函数仅释放内存可重载(全局/类)

实践建议

  • 普通堆对象:直接用 new/delete(new operator + delete operator);
  • 定制内存分配:重载 operator new/operator delete
  • 指定内存构造:用 placement new,配合手动析构和内存释放;
  • 数组:严格配对 new[]delete[],避免漏调析构。

理解这些概念后,你就能灵活应对复杂内存管理场景(如内存池、对象池),精准控制对象的生命周期与内存分配!

http://www.xdnf.cn/news/1187875.html

相关文章:

  • 初识java
  • Python 程序设计讲义(20):选择结构程序设计——双分支结构的简化表示(三元运算符)
  • Model Control Protocol 三层架构设计,三种传输方式,完成MCP项目构建实现工具调试,多维度评价指标检测多工具多资源调用的鲁棒性和稳健性
  • java面试题(二)
  • 栈----1.有效的括号
  • 扒网站工具 HTTrack Website Copier
  • 3020雕刻机脱机自定义指令
  • 一些常见的网络攻击方式
  • 疯狂星期四第19天运营日记
  • Java并发编程第十篇(ThreadPoolExecutor线程池组件分析)
  • 锁相环技术简介(面向储能变流器应用)
  • 机器学习(一)KNN,K近邻算法(K-Nearest Neighbors)
  • [硬件电路-85]:一款高集成度热电制冷器(TEC)控制器芯片ADN8835ACPZ
  • 工程师实践出真知
  • 【Spring WebFlux】为什么 Spring 要拥抱响应式
  • java面试题(一)
  • 基于深度学习的图像分类:使用DenseNet实现高效分类
  • 解决 Delete ␍ prettier/prettier问题的方案
  • TwinCAT3编程入门1
  • 理解Spring中的IoC
  • 探索 MyBatis-Plus
  • [2025CVPR-图象分类方向]SPARC:用于视觉语言模型中零样本多标签识别的分数提示和自适应融合
  • TDengine 转化函数 TO_UNIXTIMESTAMP 用户手册
  • S7-1500 与 ET200MP 的组态控制通信(Configuration Control)功能实现详解(下)
  • 【vue3+vue-pdf-embed】实现PDF+图片预览
  • 文件被删除了怎么恢复?恢复方法总结与重点注意事项
  • Mysql 日志 binlog redolog
  • deepseek本地部署,轻松实现编程自由
  • 在线事务型的业务、实时分析类业务、离线处理类型的业务
  • 数据赋能(332)——安全与合规——保密管理