重载
通过对operator new和和new expression的学习,了解到这两个到最底层仍然是通过调用malloc和free来对内存进行申请与释放的,如下图所示
不能重载new,因为new是一个表达式,::operator new是全局的,它的应用较为广泛,如果重载它可能会导致一些未知错误(但是其仍然是支持重载的),Foo::operator new是最合适的重载人选。重载的目的是为了尝试减少malloc申请内存时的cookie。
对::operator new进行重载,首先不能声明在一个命名空间中(namespace),其次必须为内联函数
对Foo::operator new的重载
对 array new的重载
重载operator new和array new
测试例程
#include<iostream>
#include <cstddef>
#include <iostream>
#include <string>
using namespace std;
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; }//virtual
/*不加 virtual dtor, sizeof = 12, new Foo[5] => operator new[]() 的 size 參數是 64,
* 加了 virtual dtor, sizeof = 16, new Foo[5] => operator new[]() 的 size 參數是 84,
* 上述二例,多出來的 4 可能就是個 size_t 欄位用來放置 array size. */
};
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);
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";// 因为有全局符号,所以會繞過 overloaded new(), delete(), new[](), delete[]()
Foo* p = ::new Foo(7);// 但當然 ctor, dtor 都會被正常呼叫.
::delete p;
Foo* pArray = ::new Foo[5];
::delete [] pArray;
}
}
int main()
{
test_overload_operator_new_and_array_new();
return 0;
}
这里对运行结果进行解释
重载placement new时,第一参数必须是size_t(unsigned int)类型,如果不是则会出错。在重载operator delete时,对于含参的构造函数必须使用抛出错误才能够调用重载的delete,其设计原因是怕用户重载的operator new不能将对象完整的建立起来,但是内存已经分配,用户从抛出这个过程来调用自己的operator delete来回收内存。
placement new例程
#include <vector>
#include<iostream>
using namespace std;
{
class Bad { };
class Foo
{
public:
Foo() { cout << "Foo::Foo()" << endl; }
Foo(int) {
cout << "Foo::Foo(int)" << endl;
throw Bad();
}
/*(1) 這個就是一般的 operator new() 的重載 */
void* operator new(size_t size) {
cout << "operator new(size_t size), size= " << size << endl;
return malloc(size);
}
/*(2) 這個就是標準庫已經提供的 placement new() 的重載 (形式)
(所以我也模擬 standard placement new 的動作, just return ptr) */
void* operator new(size_t size, void* start) {
cout << "operator new(size_t size, void* start), size= " << size << " start= " << start << endl;
return start;
}
/*(3) 這個才是嶄新的 placement new */
void* operator new(size_t size, long extra) {
cout << "operator new(size_t size, long extra) " << size << ' ' << extra << endl;
return malloc(size+extra);
}
/*(4) 這又是一個 placement new */
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);
}
/*以下是搭配上述 placement new 的各個 called placement delete.
當 ctor 發出異常,這兒對應的 operator (placement) delete 就會被喚起.
應該是要負責釋放其搭檔兄弟 (placement new) 分配所得的 memory.
(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); //op-new(size_t,long,char)
Foo* p7 = new (&start) Foo(1); //op-new(size_t,void*)
Foo* p8 = new Foo(1); //op-new(size_t)
}
int main()
{
test_overload_placement_new();
return 0;
}
程序执行到p5时就会终止,因为它调用了含参构造函数,含参构造函数进行了异常的抛出。
运行结果
将异常抛出屏蔽掉以后
可以都正常运行,调用各种重载已经在注释中注明。
不积小流无以成江河