new/delete管理对象生命周期并调用构造/析构函数,malloc/free仅处理裸内存;二者绝不可混用,否则导致未定义行为、资源泄漏或崩溃。

别用 malloc 释放 new 出来的内存,也别用 delete 释放 malloc 来的指针——这不是风格问题,是未定义行为,轻则资源泄漏,重则程序当场崩溃。
new 分配失败不返回 nullptr,而是抛异常
很多从 C 转过来的人习惯写 if (p == nullptr) 判断 new 是否成功,这毫无意义:new 默认根本不会返回 nullptr,失败直接抛 std::bad_alloc。你没捕获,程序就 terminate。
- 要获得类似
malloc的行为,得显式用new (std::nothrow),它失败才返回nullptr -
malloc失败返回NULL(或nullptr),必须手动检查;new默认走异常路径,适合 RAII 场景 - 混用错误处理风格(比如在异常关闭的模块里用
new却不 try/catch)容易漏掉崩溃点
new/delete 管对象生命周期,malloc/free 只管内存块
new Widget 做三件事:调 operator new 分配原始内存 → 在那块地址上调 Widget 构造函数 → 返回 Widget*;delete 则反向:先调析构函数 → 再调 operator delete 归还内存。而 malloc(sizeof(Widget)) 就只是拿一块裸内存,字段全为垃圾值,析构函数压根不会触发。
- 对类类型(含
std::string、std::vector等成员),用malloc+ 手动placement new是可行但高危操作,漏掉析构 = 资源泄漏 - 用
free释放new指针,跳过析构 → 成员对象的资源(文件句柄、堆内存等)永不释放 - 内置类型(如
int、double)看似没区别,但语义断裂:你写new int[100],就该配delete[],不是free
new 是类型安全的运算符,malloc 是无类型的库函数
new int[5] 编译器知道要分配 5 * sizeof(int) 字节,并返回 int*;malloc(5) 只拿到 5 字节,你还得自己 cast 成 int*,编译器无法校验这个转换是否合理。
立即学习“C++免费学习笔记(深入)”;
-
malloc返回void*,C++11 起隐式转int*已被禁止,必须写(int*)malloc(...)或static_cast<int>(...)</int> - 重载
operator new可定制分配逻辑(比如内存池),malloc是固定实现,只能包装 -
new[]和delete[]隐含额外元数据(如数组长度),用于正确调用多个析构函数;malloc没这层机制,free也不关心你当初是不是当数组用的
自由存储区 ≠ 堆,但默认实现通常复用 malloc/free
标准里说 new 从“自由存储区”(free store)分配,malloc 从“堆”(heap)分配——听起来像两个地方,其实绝大多数编译器下,operator new 底层就是调 malloc,operator delete 调 free。真正区别在于语义层:前者是 C++ 对象模型的一部分,后者是 C 的原始内存接口。
- 你可以重载
operator new让它从 mmap 映射的页、栈内存甚至预分配缓冲区里取空间,此时“自由存储区”就真不是堆了 -
placement new更极端:它根本不分配内存,只在你给的地址上调构造函数,delete也不能直接用,得手动调析构 + 不调operator delete - 跨语言混编(比如 C 接口回调 C++ 对象)时,务必明确内存所有权归属:谁分配、谁释放,不能靠“看起来都是堆”来蒙混
最常被忽略的一点:数组场景下 new T[n] 和 malloc(n * sizeof(T)) 表面等价,但前者隐含析构数组每个元素的责任,后者连这个概念都没有——一旦 T 有非平凡析构函数,混用等于埋雷。


















