在 C++ 中,operator new
和 operator delete
是用于动态内存分配和释放的运算符。重载这两个运算符可以使你在分配或释放内存时添加额外的行为,例如跟踪内存使用情况或实现自定义的内存池。
operator new
和 operator delete
支持全局重载以及类内重载。全局重载允许在整个程序中统一管理内存分配和释放行为,而类内重载则提供了针对特定类的自定义内存管理方式,允许开发者为该类的对象分配和释放内存时实施特定的策略。operator new[]
和 operator delete[]
也是类似地支持全局和类内重载,用于处理动态数组的内存管理。
1. 全局重载
可以在任何地方定义重载的 operator new
和 operator delete
,使得所有对象的内存分配和释放行为遵循自定义逻辑。
1. 演示
- 如何重载标准的内存分配/释放函数?
- 如何重载带有额外参数的内存分配和释放函数?
#if 1 #include <iostream> using namespace std; struct Demo { Demo() { cout << "Demo 构造函数" << endl; } ~Demo() { cout << "Demo 析构函数" << endl; } }; // 1. 如何重载标准的内存分配/释放函数? void* operator new(size_t size) { cout << "对象内存分配函数" << endl; return malloc(size);; } void operator delete(void* ptr) { cout << "对象内存释放函数" << endl; free(ptr); } void* operator new[](size_t size) { cout << "数组内存分配函数" << endl; return malloc(size);; } void operator delete[](void* ptr) { cout << "数组内存释放函数" << endl; free(ptr); } void test01() { Demo* d1 = new Demo; delete d1; int* d2 = new int; delete d2; Demo* d3 = new Demo[2]; delete[] d3; } // 2. 如何重载带有额外参数的内存分配和释放函数? /* 带额外参数的 operator new/delete 允许对象分配内存时,传入额外的信息 需要注意的是: 1. 每个重载的 operator new 都应该有对应的 operator delete,即:成对出现 2. 任意版本的 operator new 分配的内存: 2.1 正常情况下,手动由标准的 delete 运算符调用标准的 operator delete 函数释放 2.2 异常情况下,自动由 oeprator new 对应的 operator delete 函数释放 */ struct Sample { Sample() { cout << "Sample 构造函数" << endl; throw exception(); } ~Sample() { cout << "Sample 析构函数" << endl; } }; void* operator new(size_t size, const char* file, int line) { cout << "非标准的对象内存分配函数,文件:" << file << " 行号:" << line << endl; return malloc(size); } void operator delete(void* ptr, const char* file, int line) { cout << "非标准的对象内存释放函数,文件:" << file << " 行号:" << line << endl; free(ptr); } void* operator new[](size_t size, const char* file, int line) { cout << "非标准的数组内存分配函数,文件:" << file << " 行号:" << line << endl; void* ptr = malloc(size); return ptr; } void operator delete[](void* ptr, const char* file, int line) { cout << "非标准的数组内存释放函数,文件:" << file << " 行号:" << line << endl; free(ptr); } void test02() { try { // 单个对象 Sample* s1 = new(__FILE__, __LINE__) Sample; delete s1; // 对象数组 Sample* s2 = new Sample[3]; delete[] s2; } catch (const std::exception&) { cout << "处理异常" << endl; } } int main() { test01(); test02(); return 0; } #endif
2. 问题
在全局重载 operator new/delete 会使得程序出现一些问题:
- 全局重载 operator new/delete 会影响程序动态对象的创建和销毁
- 全局重载 operator new/delete 会影响到程序依赖库(标准库、第三方库)的使用。
- 依赖库中在全局重载 operator new/delete,会使得我们的程序使用库中的内存分配行为
- 在程序中全局重载的 operator new/delete,会使得第三方库的使用我们的内存分配行为
- 如果程序和依赖库都重载了 operator new/delete 会导致重定义
- 程序中全局重载 operator delete,可能会导致 STL 容器使用出现问题
#if 1 #include <iostream> #include <unordered_map> using namespace std; struct MemInfo { const char* file; int line; }; unordered_map<void*, MemInfo> records; void* operator new(size_t size, const char* file, int line) { cout << "内存分配函数" << endl; void* ptr = malloc(size); records[ptr] = { file, line }; return ptr; } void operator delete(void* ptr) { cout << "内存释放函数" << endl; records.erase(ptr); free(ptr); } void detect_memory_leak() { if (records.size() > 0) { cout << "检测到内存泄漏" << endl; for (auto& item : records) { cout << item.second.file << " " << item.second.line << endl; } } } #define new new(__FILE__, __LINE__) void test() { int* p1 = new int; int* p2 = new int; delete p1; // 检测内存泄漏 detect_memory_leak(); } int main() { test(); return 0; } #endif
2. 类内重载
在类的定义中可以定义重载的 operator new
和 operator delete
,从而只影响该类的实例。这对于提供特定类的内存管理策略非常有用。
- 如何在类内重载标准内存分配和释放函数?
- 类内重载带额外参数的内存分配和释放函数?
#if 1 #include <iostream> using namespace std; void* operator new(size_t size) { cout << "全局对象内存分配函数" << endl; return malloc(size);; } void operator delete(void* ptr) { cout << "全局对象内存释放函数" << endl; free(ptr); } void* operator new[](size_t size) { cout << "全局数组内存分配函数" << endl; return malloc(size);; } void operator delete[](void* ptr) { cout << "全局数组内存释放函数" << endl; free(ptr); } // 1. 如何在类内重载标准内存分配和释放函数? /* 1.1 类内重载的内存分配函数必须是静态成员函数 1.2 类内重载的内存分配函数只能影响该类对象的创建 */ struct Demo { Demo() { // throw exception(); } void* operator new(size_t size) { cout << "对象内存分配函数" << endl; return malloc(size);; } void operator delete(void* ptr) { cout << "对象内存释放函数" << endl; free(ptr); } void* operator new[](size_t size) { cout << "数组内存分配函数" << endl; return malloc(size);; } void operator delete[](void* ptr) { cout << "数组内存释放函数" << endl; free(ptr); } void* operator new(size_t size, const char* file, int line) { cout << "非标准对象内存分配函数" << endl; return malloc(size);; } void operator delete(void* ptr, const char* file, int line) { cout << "非标准对象内存释放函数" << endl; free(ptr); } void* operator new[](size_t size, const char* file, int line) { cout << "非标准数组内存分配函数" << endl; return malloc(size);; } void operator delete[](void* ptr, const char* file, int line) { cout << "非标准数组内存释放函数" << endl; free(ptr); } }; void test01() { // 本类型对象创建使用类内重载的函数 // 调用类内内存分配函数 + 构造函数 // 析构函数 + 调用类内内存释放函数 Demo* d1 = new Demo; delete d1; Demo* d2 = new Demo[3]; delete[] d2; // 可以用过全局作用域运算符指定使用全局 // 调用全局内存分配函数 + 构造函数 // 析构函数 + 调用全局内存释放函数 Demo* d3 = ::new Demo; ::delete d3; Demo* d4 = ::new Demo[3]; ::delete[] d4; // 其他类型不会受到影响 int* p = new int; delete p; } // 2. 类内重载带额外参数的内存分配和释放函数? /* 1. 每个重载的 operator new 都应该有对应的 operator delete,即:成对出现 2. 任意版本的 operator new 分配的内存: 2.1 正常情况下,手动由标准的 delete 运算符调用标准的 operator delete 函数释放 2.2 异常情况下,自动由 oeprator new 对应的 operator delete 函数释放 */ void test02() { try { Demo* d1 = new(__FILE__, __LINE__) Demo; delete d1; Demo* d2 = new(__FILE__, __LINE__) Demo[3]; delete[] d2; } catch (const std::exception&) { cout << "捕获异常" << endl; } } int main() { test01(); return 0; } #endif