51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

C++ operator new/delete 函数重载

在 C++ 中,operator newoperator delete 是用于动态内存分配和释放的运算符。重载这两个运算符可以使你在分配或释放内存时添加额外的行为,例如跟踪内存使用情况或实现自定义的内存池。

operator newoperator delete 支持全局重载以及类内重载。全局重载允许在整个程序中统一管理内存分配和释放行为,而类内重载则提供了针对特定类的自定义内存管理方式,允许开发者为该类的对象分配和释放内存时实施特定的策略。operator new[]operator delete[] 也是类似地支持全局和类内重载,用于处理动态数组的内存管理。

  1. 全局重载 {#title-0} ==================

可以在任何地方定义重载的 operator newoperator delete,使得所有对象的内存分配和释放行为遵循自定义逻辑。

  1. 演示 {#title-1}

  1. 如何重载标准的内存分配/释放函数?
  2. 如何重载带有额外参数的内存分配和释放函数?
#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
  1. 问题 {#title-2}

在全局重载 operator new/delete 会使得程序出现一些问题:

  1. 全局重载 operator new/delete 会影响程序动态对象的创建和销毁
  2. 全局重载 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
  1. 类内重载 {#title-3} ==================

在类的定义中可以定义重载的 operator newoperator delete,从而只影响该类的实例。这对于提供特定类的内存管理策略非常有用。

  1. 如何在类内重载标准内存分配和释放函数?
  2. 类内重载带额外参数的内存分配和释放函数?
#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

赞(2)
未经允许不得转载:工具盒子 » C++ operator new/delete 函数重载