在 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

 冀公网安备13050302001966号
 冀公网安备13050302001966号