new会调用构造函数而malloc不会,这是最核心区别;new分配内存后自动初始化对象并返回类型安全指针,malloc仅分配原始字节且需手动转换与管理。

new 会调用构造函数,malloc 不会
这是最核心的区别。当你用 new 分配对象时,编译器不仅分配内存,还会自动调用对应类型的构造函数;而 malloc 只做一件事:从堆上申请原始字节,不涉及任何类型信息或初始化逻辑。
常见错误现象:
用 malloc 分配 std::string 或带成员对象的类,结果对象处于未定义状态——std::string 的内部指针没被初始化,后续调用 c_str() 或析构时直接崩溃。
-
new MyClass()→ 先分配内存,再调用MyClass::MyClass() -
malloc(sizeof(MyClass))→ 只返回void*,MyClass的成员变量全是垃圾值 - 若类有虚函数表指针(vptr),
malloc后该指针未设置,多态调用必出错
new 返回带类型的指针,malloc 返回 void*
new 返回的是具体类型的指针(如 int*、Widget*),天然支持类型检查和自动解引用;malloc 强制返回 void*,必须显式 static_cast 或 C 风格强制转换,否则编译失败(C++ 中不允许隐式转换)。
使用场景差异:
在泛型容器或底层内存池中,有时会混用 malloc + placement new,但那是高级用法;日常对象创建,new 的类型安全是刚需。
立即学习“C++免费学习笔记(深入)”;
-
int* p = new int(42);—— 类型匹配,无需转换 -
int* p = (int*)malloc(sizeof(int));—— C 风格转换,C++ 中更推荐static_cast(malloc(...)) - 如果忘了转换,
int* p = malloc(sizeof(int));在 C++ 中直接编译报错:cannot convert 'void*' to 'int*'
new 和 malloc 的内存释放方式不能交叉使用
这是最容易踩的坑:用 new 分配的内存必须用 delete 释放,用 malloc 分配的必须用 free。混用会导致未定义行为——常见表现是程序偶发崩溃、内存泄漏、或析构函数完全不执行。
原因在于:delete 内部会先调用析构函数,再调用 operator delete(底层可能调用 free,但不保证);而 free 完全不知道析构这回事。
-
int* p = new int(10); delete p;✅ 正确 -
int* p = new int(10); free(p);❌ 析构未触发,且可能破坏堆管理器内部结构 -
int* p = (int*)malloc(sizeof(int)); delete p;❌ 可能跳转到随机地址执行“析构”,因为delete会尝试读取 vtable 或调用 operator delete 匹配的版本
数组 new[] 和 malloc 的长度管理差异
用 new[] 分配数组时,编译器通常会在实际分配的内存前额外存储数组长度(用于 delete[] 知道要调用几次析构函数);malloc 完全不记录这个信息,所有长度必须由程序员自己维护。
性能与兼容性影响:new[] 的额外开销极小(一般就几个字节),但换来的是类型安全和自动析构;而 malloc + 手动管理长度 + 手动循环调用构造/析构,代码量大、易出错、且无法享受 RAII。
-
MyClass* arr = new MyClass[10];→ 分配 10 个对象,每个都调用默认构造函数 -
MyClass* arr = (MyClass*)malloc(10 * sizeof(MyClass));→ 内存有了,但 10 个对象全未构造 - 若真要用
malloc模拟对象数组,得配合 placement new:new(arr + i) MyClass(),且后续必须手动对每个元素调用arr[i].~MyClass()
类型安全不是可选项,是 C++ 对象生命周期的基础设施。哪怕只漏掉一次构造或析构,问题也可能延迟到程序退出前才暴露。









