0

0

C++ operator new和new区别 C++内存分配与构造函数调用分离【深度】

冰火之心

冰火之心

发布时间:2026-01-24 12:59:02

|

856人浏览过

|

来源于php中文网

原创

operator new仅分配内存而不调用构造函数,必须配合placement new或new表达式(自动调用构造)使用;其重载需配对实现operator delete,且数组形式须分别重载operator new[]/delete[]。

c++ operator new和new区别 c++内存分配与构造函数调用分离【深度】

operator new 只分配内存,不调用构造函数

operator new 是一个纯内存分配函数,行为上等价于 C 的 malloc:它只向系统申请原始字节空间,返回 void*,完全不涉及类型信息或对象生命周期。你不能直接用它创建可用的对象实例——哪怕类有默认构造函数,它也绝不会被调用。

常见错误是误以为 operator new(sizeof(MyClass)) 能得到一个已构造的 MyClass 对象,结果后续直接调用成员函数就会崩溃(未定义行为,通常因 this 指针指向未初始化内存)。

  • 典型使用场景:配合 placement new 实现自定义对象布局,比如内存池、对象数组预分配、序列化反序列化时跳过构造
  • 它可被重载:类内声明 static void* operator new(size_t) 会覆盖全局版本;重载时必须返回非空指针,否则抛 std::bad_alloc
  • 注意:operator new[]operator delete[] 必须成对重载,否则 new T[N] 行为不可靠

new 表达式 = operator new + 构造函数调用

当你写 new MyClass(1, 2),编译器实际拆成两步:先调用 operator new(sizeof(MyClass)) 分配内存,再在该地址上调用 MyClass::MyClass(1, 2)。这两步不可分割,且构造失败时会自动调用匹配的 operator delete(不是 delete)回滚内存。

这解释了为什么自定义 operator new 抛异常后,new 表达式仍能保证强异常安全:构造函数若 throw,编译器插入的清理代码会调用你重载的 operator delete(前提是签名匹配)。

立即学习C++免费学习笔记(深入)”;

  • 如果类重载了 operator new 但没提供对应 operator delete,构造异常时可能内存泄漏
  • new (std::nothrow) MyClass 不影响构造函数调用,只是让第一步 operator new 失败时返回 nullptr 而非抛异常
  • 数组形式 new MyClass[10] 调用的是 operator new[](size_t),不是 operator new

placement new 是唯一合法的“只构造不分配”方式

标准库提供的 operator new(std::size_t, void* p)(即 placement new)不分配内存,只返回传入的 p。它存在的唯一目的,就是在已知地址上显式调用构造函数:

ReRoom AI
ReRoom AI

专为室内设计打造的AI渲染工具,可以将模型图、平面图、草图、照片转换为高质量设计效果图。

下载
char buffer[sizeof(MyClass)];
MyClass* obj = new (buffer) MyClass(42); // 在 buffer 上构造

这里 new (buffer) 是语法糖,底层就是调用 MyClass::MyClass(42)buffer 必须足够大且对齐正确(可用 alignas(MyClass) 保证)。

  • 必须手动调用析构函数:obj->~MyClass(),否则资源泄漏
  • 不能用 delete obj 销毁它——因为没用 operator new 分配,delete 会尝试调用 operator delete 去释放非法地址
  • 自定义 placement new(如带额外参数)需自行声明,编译器不自动识别;标准 placement new 不抛异常,也不检查 p 是否为空

operator delete 和 delete 表达式的对应关系容易混淆

delete ptr 表达式也分两步:先调用对象的析构函数,再调用 operator delete(ptr) 释放内存。关键点在于:它调用的 operator delete 版本,由与之配对的 new 表达式所用的 operator new 决定

例如:new (std::nothrow) T 分配的内存,必须用 delete(而非 delete nothrow)销毁;而 new T 分配的,若用 delete 但类只重载了 operator delete(void*, std::nothrow_t),则链接失败或调用错误版本。

  • 全局 operator delete(void*) 是所有普通 new 的兜底释放函数;若类重载了它,delete 就调用类版本
  • 数组删除 delete[] ptr 必须匹配 operator new[],否则未定义行为(常见 crash 点)
  • 自定义 operator delete 应声明为 noexcept,否则析构后释放失败可能导致程序终止

C++ 的内存分配和对象构造从设计上就是解耦的,但这种解耦只在你明确需要控制时才有价值。多数情况下,直接用 newdelete 就够了;一旦开始重载 operator new 或用 placement new,就必须同步处理所有配套的 delete 和析构逻辑——漏掉任意一环,问题往往延迟到运行时才暴露。

相关专题

更多
javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

176

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

98

2025.11.27

空指针异常处理
空指针异常处理

本专题整合了空指针异常解决方法,阅读专题下面的文章了解更多详细内容。

22

2025.11.16

数据库Delete用法
数据库Delete用法

数据库Delete用法:1、删除单条记录;2、删除多条记录;3、删除所有记录;4、删除特定条件的记录。更多关于数据库Delete的内容,大家可以访问下面的文章。

274

2023.11.13

drop和delete的区别
drop和delete的区别

drop和delete的区别:1、功能与用途;2、操作对象;3、可逆性;4、空间释放;5、执行速度与效率;6、与其他命令的交互;7、影响的持久性;8、语法和执行;9、触发器与约束;10、事务处理。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.12.29

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

9

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

25

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

18

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

19

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 4.8万人学习

Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Pandas 教程
Pandas 教程

共15课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号