重载new和delete操作符步骤
- 重载全局new和delete操作符
void* operator new(size_t size) {
void* ptr = std::malloc(size);
if (!ptr) {
throw std::bad_alloc();
}
return ptr;
}
- **重载delete操作符**:
void operator delete(void* ptr) noexcept {
std::free(ptr);
}
- 重载类专属的new和delete操作符
class MyClass {
public:
void* operator new(size_t size) {
void* ptr = std::malloc(size);
if (!ptr) {
throw std::bad_alloc();
}
return ptr;
}
};
- **重载类专属delete操作符**:
class MyClass {
public:
void operator delete(void* ptr) noexcept {
std::free(ptr);
}
};
注意事项
- 参数要求:
new
操作符的第一个参数必须是size_t
类型,表示要分配的内存大小。delete
操作符的第一个参数必须是void*
类型,表示要释放的内存指针。
- 异常处理:全局
new
操作符在分配内存失败时应抛出std::bad_alloc
异常。delete
操作符不应抛出异常,通常应声明为noexcept
。
- 匹配规则:类专属的
new
和delete
操作符优先于全局的new
和delete
操作符被调用,所以要确保类专属的实现符合需求。
不同内存分配策略与new和delete操作符的关系
- 堆分配:
new
和delete
操作符默认进行堆分配。new
操作符从堆中分配内存,delete
操作符将堆内存释放回堆。堆分配灵活,但频繁分配释放可能导致内存碎片。
- 栈分配:栈分配由编译器自动管理,使用局部变量实现,不涉及
new
和delete
操作符。栈分配速度快,但内存大小受限于栈空间,且局部变量生命周期结束时内存自动释放。
- 内存池:内存池是一种预先分配一定大小内存块的技术。
new
操作符可从内存池中获取内存,delete
操作符将内存归还内存池。这减少了系统调用开销,避免内存碎片,但实现复杂,需要考虑内存池大小、内存块管理等。
实际项目中选择合适内存分配策略
- 频繁小对象分配:使用内存池,减少堆分配次数,提高性能并避免碎片。如游戏开发中大量小对象(如粒子系统)的管理。
- 大对象分配:若大对象生命周期长,可直接堆分配。若生命周期短且函数内使用,可考虑栈分配,但需注意栈空间限制。
- 简单场景:对性能要求不高且对象数量不多,默认堆分配(
new
和delete
默认行为)简单直接,易于实现和维护。