文章目录
- 前言
- 1 重载全局的 ::operator new 运算符
- 2 重载类的 operator new 运算符
- 3 重载类的带有额外参数的 operator new 运算符
前言
重载 operator new
运算符来自定义内存分配的行为。重载 operator new
运算符允许我们使用自定义的内存分配逻辑,例如使用池分配、内存池等。
以下是重载 operator new
运算符的几种方式:
1 重载全局的 ::operator new 运算符
void* operator new(std::size_t size) {
// 自定义内存分配逻辑
void* ptr = /* 自定义逻辑 */;
return ptr;
}
通过重载全局的 operator new
,我们可以自定义所有类的内存分配行为,注意这里一般不会这样做,因为影响太深远,涉及面广,因为程序中可能大多数类的new都是使用默认的,没有重载自身类的operator new,可能都是使用全局的 ::operator new
。
2 重载类的 operator new 运算符
class MyClass {
public:
static void* operator new(std::size_t size) {
// 自定义内存分配逻辑
void* ptr = /* 自定义逻辑 */;
return ptr;
}
};
在类中重载 operator new
运算符,可以针对该类自定义内存分配的行为。
因为new往往是在创建对象的时候,所以不是对象的方法,应该是static。
示例代码
class Foo
{
public:
int _id;
long _data;
string _str;
public:
static void* operator new(size_t size);
static void operator delete(void* deadObject, size_t size);
static void* operator new[](size_t size);
static void operator delete[](void* deadObject, size_t size);
Foo() : _id(0) { cout << "default ctor. this=" << this << " id=" << _id << endl; }
Foo(int i) : _id(i) { cout << "ctor. this=" << this << " id=" << _id << endl; }
~Foo() { cout << "dtor. this=" << this << " id=" << _id << endl; }
};
void* Foo::operator new(size_t size)
{
Foo* p = (Foo*)malloc(size);
cout << "Foo::operator new(), size=" << size << "\t return: " << p << endl;
return p;
}
void Foo::operator delete(void* pdead, size_t size)
{
cout << "Foo::operator delete(), pdead= " << pdead << " size= " << size << endl;
free(pdead);
}
void* Foo::operator new[](size_t size)
{
Foo* p = (Foo*)malloc(size); //crash, 問題可能出在這兒
cout << "Foo::operator new[](), size=" << size << "\t return: " << p << endl;
return p;
}
void Foo::operator delete[](void* pdead, size_t size)
{
cout << "Foo::operator delete[](), pdead= " << pdead << " size= " << size << endl;
free(pdead);
}
void test_overload_operator_new_and_array_new()
{
cout << "\ntest_overload_operator_new_and_array_new().......... \n";
cout << "sizeof(Foo)= " << sizeof(Foo) << endl;
{
Foo* p = new Foo(7);
delete p;
Foo* pArray = new Foo[5]; //無法給 array elements 以 initializer
delete [] pArray;
}
{
cout << "testing global expression ::new and ::new[] \n";
// 直接调用全局的 ::new 这会绕过 overloaded new(), delete(), new[](), delete[]()
// 但 ctor, dtor 都会被正常调用.
Foo* p = ::new Foo(7);
::delete p;
Foo* pArray = ::new Foo[5];
::delete [] pArray;
}
}
3 重载类的带有额外参数的 operator new 运算符
void* operator new(std::size_t size, AdditionalArgs args) {
// 自定义内存分配逻辑,可以使用额外的参数
void* ptr = /* 自定义逻辑 */;
return ptr;
}
通过重载带有额外参数的 operator new
,我们可以在内存分配过程中传递额外的参数,以便进行更复杂的内存管理。
在重载 operator new
运算符时,注意以下几点:
- 返回值类型必须为
void*
,表示分配的内存地址。 - 第一个参数是
std::size_t size
,表示要分配的内存大小。 - 可以有额外的参数,以满足特定需求。
- 可以使用任何自定义的内存分配逻辑,例如使用
malloc
、内存池等。 - 注意处理错误和异常情况,确保内存分配成功。
示例代码
class Foo
{
public:
Foo() { cout << "Foo::Foo()" << endl; }
Foo(int) {
cout << "Foo::Foo(int)" << endl;
}
//(1) 这个就是一般的 operator new() 的重载
void* operator new(size_t size) {
cout << "operator new(size_t size), size= " << size << endl;
return malloc(size);
}
//(2) 这个就是标准库已经提供的 placement new() 的重载 (形式)
void* operator new(size_t size, void* start) {
cout << "operator new(size_t size, void* start), size= " << size << " start= " << start << endl;
return start;
}
void* operator new(size_t size, long extra) {
cout << "operator new(size_t size, long extra) " << size << ' ' << extra << endl;
return malloc(size+extra);
}
void* operator new(size_t size, long extra, char init) {
cout << "operator new(size_t size, long extra, char init) " << size << ' ' << extra << ' ' << init << endl;
return malloc(size+extra);
}
//(1) 这是对应一般的 operator delete() 的重載
void operator delete(void*,size_t)
{ cout << "operator delete(void*,size_t) " << endl; }
//(2) 这是对应上述的 (2)
void operator delete(void*,void*)
{ cout << "operator delete(void*,void*) " << endl; }
//(3) 这是对应上述的 (3)
void operator delete(void*,long)
{ cout << "operator delete(void*,long) " << endl; }
//(4) 这是对应上述的 (4)
//如果沒有一一对应, 也不会有任何编译错误
void operator delete(void*,long,char)
{ cout << "operator delete(void*,long,char) " << endl; }
private:
int m_i;
};
void test_overload_placement_new()
{
cout << "\n\n\ntest_overload_placement_new().......... \n";
Foo start; //Foo::Foo
Foo* p1 = new Foo; //op-new(size_t)
Foo* p2 = new (&start) Foo; //op-new(size_t,void*)
Foo* p3 = new (100) Foo; //op-new(size_t,long)
Foo* p4 = new (100,'a') Foo; //op-new(size_t,long,char)
Foo* p5 = new (100) Foo(1); //op-new(size_t,long) op-del(void*,long)
Foo* p6 = new (100,'a') Foo(1); //
Foo* p7 = new (&start) Foo(1); //
Foo* p8 = new Foo(1); //
}
//VC6 warning C4291: ‘void *__cdecl Foo::operator new(unsigned int)’
//no matching operator delete found; memory will not be freed if
//initialization throws an exception
这表示对对应的new调用的构造函数的异常不做处理。所以这里delete参数实际上是对应异常的类型。
将构造函数抛出异常,然后打印。这里要注意将调用的代码即test_overload_placement_new
使用try catch包含,否则无法捕获异常。
Foo(int) {
cout << "Foo::Foo(int)" << endl;
throw 1;
}
可以看到,operator delete(void*,long)
是执行了。
当然异常抛出以后后面的自然也就不执行了。