文章目录
- 前言
- 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::FooFoo* 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)
是执行了。
当然异常抛出以后后面的自然也就不执行了。