# A06 —— new/delete 和 malloc/free:C++ 内存管理的区别

**金句**:new 不是 malloc,delete 不是 free——它们不只是分配,还有构造和析构。

## new 和 malloc 的本质区别

“`
new 和 malloc 的区别:

malloc:
– C 库函数
– 只分配内存,不初始化
– 返回 void*
– 失败返回 NULL

new:
– C++ 关键字
– 分配内存 + 调用构造函数
– 返回具体类型的指针(不需要类型转换)
– 失败抛出 std::bad_alloc

// malloc 示例
int *p = (int*)malloc(sizeof(int));
*p = 42; // 必须手动初始化

// new 示例
int *p = new int(42); // 分配 + 初始化
“`

“`
new 的底层实现:

void* operator new(size_t size) {
if (size == 0) size = 1;

// 尝试分配
void *p = malloc(size);

// 分配失败,调用 new_handler
while (p == nullptr) {
std::new_handler h = std::get_new_handler();
if (h) (*h)();
else throw std::bad_alloc();
p = malloc(size);
}

return p;
}

new 实际上调用 malloc!
delete 实际上调用 free!
“`

## new 和 delete 对对象的作用

“`
new 对对象:

class A {
int x;
public:
A(int v) : x(v) {}
};

A *p = new A(10);

等价于:
1. void *temp = operator new(sizeof(A)); // malloc
2. A *p = static_cast(temp);
3. p->A(10); // 调用构造函数

delete 对对象:

delete p;

等价于:
1. p->~A(); // 调用析构函数
2. operator delete(p); // free

构造和析构是 new/delete 和 malloc/free 的本质区别!
“`

“`
数组的 new[] 和 delete[]:

A *arr = new A[10]; // 分配 10 个 A 对象
delete[] arr; // 销毁 10 个对象

等价于:
1. A *arr = (A*)operator new[] (10 * sizeof(A));
2. 构造 10 个对象
3. 调用 10 次析构函数
4. operator delete[] (arr)

注意:
delete[] 必须和 new[] 配对
用 delete(不带[])销毁数组会导致 UB
“`

## placement new

“`
placement new:在指定地址构造对象

#include

char buf[sizeof(A)];
A *p = new(buf) A(10); // 在 buf 上构造 A

等价于:
void *temp = buf;
A *p = static_cast(temp);
p->A(10);

用途:
– 预先分配的内存上构造对象
– 内存池
– 对象构造/析构灵活控制

显式析构(placement delete):
p->~A(); // 只调用析构,不释放内存
“`

## operator new 可以重载

“`
可以自定义 operator new:

class MyClass {
public:
static void* operator new(size_t size) {
// 自定义分配逻辑
// 比如从对象池分配
return pool.allocate(size);
}

static void operator delete(void* p) {
// 自定义释放逻辑
pool.deallocate(p);
}
};

所有 MyClass 的 new 都走这个函数。
全局 operator new 可以被所有类型使用。
“`

## 总结

– **malloc**:只分配内存,不初始化,返回 void*
– **new**:分配内存 + 调用构造函数,返回具体类型指针,失败抛异常
– **operator new**:底层调用 malloc,new 是 operator new + 构造
– **delete**:调用析构 + operator delete(底层 free)
– **new[]/delete[]**:构造/析构数组,必须配对使用
– **placement new**:在指定地址构造对象,不分配内存

**下篇预告(A07)**:什么是内存池?预先分配大块内存,按需分配——为什么游戏服务器常用内存池来避免 malloc。

*关注公众号「AI不着急」,回复”资料”获取内存学习路线图。*

最后修改: 2024年7月31日

作者

评论

发表评论

您的邮箱地址不会被公开。