1. new 和 malloc 的区别解析
作为C++开发者,内存管理是最基础也最容易被问到的知识点。我面试过上百位候选人,这个问题几乎每次必问。很多人能背出几点区别,但真正理解背后原理的并不多。
1.1 语言层面的本质差异
new是C++的运算符(operator),就像+、-、*一样是语言内置的操作符。这意味着:
- 编译器会为new生成特定的代码序列
- 可以重载operator new来定制内存分配行为
- 类型安全:编译器知道分配的对象类型
malloc则是C标准库函数(stdlib.h),它的行为更底层:
- 只是简单地向操作系统申请一块内存
- 对内存用途一无所知
- 返回void*需要手动类型转换
关键点:new是"聪明的"内存分配,malloc是"愚蠢的"内存分配。就像智能家居开关和普通开关的区别。
1.2 构造与析构的魔法
new最核心的价值在于它会自动调用构造函数:
cpp复制class MyClass {
public:
MyClass() { cout << "构造" << endl; }
~MyClass() { cout << "析构" << endl; }
};
MyClass* obj = new MyClass(); // 输出"构造"
delete obj; // 输出"析构"
而malloc/free完全不知道什么是构造/析构:
cpp复制MyClass* obj = (MyClass*)malloc(sizeof(MyClass)); // 无输出
free(obj); // 无输出
这会导致严重问题:
- 对象可能处于未初始化状态
- 资源(文件句柄、锁等)可能泄漏
1.3 错误处理机制对比
当内存不足时:
- new会抛出std::bad_alloc异常
- malloc返回NULL指针
现代C++更推荐异常机制,因为:
- 异常不能被忽略,强制处理
- 异常可以携带更多错误信息
- 与RAII模式天然契合
1.4 实际项目中的选择建议
在混合编程时要注意:
- malloc分配的内存要用free释放
- new分配的内存要用delete释放
- new[]分配数组要用delete[]释放
常见坑点:
- 用delete释放malloc内存 → 未定义行为
- 用free释放new的内存 → 不会调用析构函数
- 忘记匹配的[] → 内存泄漏
2. new的底层实现揭秘
2.1 两步走的过程
new实际上做了两件事:
- 分配内存:调用operator new
- 构造对象:调用构造函数
operator new的典型实现:
cpp复制void* operator new(size_t size) {
void* p = malloc(size); // 最终还是调用malloc
if (!p) throw bad_alloc();
return p;
}
2.2 自定义内存管理
我们可以重载operator new:
cpp复制class MyClass {
public:
static void* operator new(size_t size) {
cout << "自定义内存分配" << endl;
return ::operator new(size);
}
};
特殊用法placement new:
cpp复制char buf
