重载

通过对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时就会终止,因为它调用了含参构造函数,含参构造函数进行了异常的抛出。

运行结果

 

 将异常抛出屏蔽掉以后

 

 可以都正常运行,调用各种重载已经在注释中注明。

posted @ 2019-12-17 11:56  C_hp  阅读(217)  评论(0编辑  收藏  举报