在 C++ 中,operator new
和 operator delete
是用于动态内存分配和释放的运算符。重载这两个运算符可以使你在分配或释放内存时添加额外的行为,例如跟踪内存使用情况或实现自定义的内存池。
operator new
和 operator delete
支持全局重载以及类内重载。全局重载允许在整个程序中统一管理内存分配和释放行为,而类内重载则提供了针对特定类的自定义内存管理方式,允许开发者为该类的对象分配和释放内存时实施特定的策略。operator new[]
和 operator delete[]
也是类似地支持全局和类内重载,用于处理动态数组的内存管理。
- 全局重载 {#title-0} ==================
可以在任何地方定义重载的 operator new
和 operator delete
,使得所有对象的内存分配和释放行为遵循自定义逻辑。
- 演示 {#title-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
- 问题 {#title-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
- 类内重载 {#title-3} ==================
在类的定义中可以定义重载的 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