new, operator new, placement new

一 new (new operator) 與 operator new
對象的動態創建方法:
new T;
實質是包含兩個階段的操作:
1使用 operator new進行內存分配: void* operator new(size_t size)。
2調用對應構造函數進行構造。
我們可以改寫全局的operator new從而進行自己的內存分配,可以通過malloc函數實現
/// Create time: 2014-7-29 09:14:39 By ldlan
/// C++, VS2010
#include <iostream>
using namespace std;

//改寫全局的operator new函數進行內存分配
void* operator new(size_t size)
{
	void* p = malloc(size);
	return p;
}

class Time
{
private:
	int year, month, day;
public:
	Time():year(1970),month(1),day(1){}
};

int main(void)
{
	// 將會調用到自定義的operator new函數
	Time *today = new Time;
	
	delete today;
	return 0;
}
同時非常必要的要對 operator delete 進行改寫
void operator delete(void *p)
{
	free(p);
}
使用delete p;與new T;相反的(1)先進行對象析構(類類型),(2)之後調用operator delete;進行內存的釋放。

同時也可以使operator new成爲類的成員函數,這樣在進行new創建對象時將根據對象自動識別(this)並進行調用operator new函數進行內存的分配,代碼如下
class Time
{
private:
	int year, month, day;
public:
	Time():year(1970),month(1),day(1){}
	~Time(){
	}	
	// 將operator new定義爲成員函數
	void* operator new(size_t size)
	{
		void* p = malloc(size);
		return p;
	}
	// 將operator delete定義爲成員函數
	void operator delete(void *p)
	{
		free(p);
	}
};
有時候即使在類成員函數中進行內存分配時仍然只是使用外部的全局分配的方式,我們也可以調用全局的內存分配函數:
class Time
{
private:
	int year, month, day;
public:
	Time():year(1970),month(1),day(1){}
	~Time(){
	}
	void* operator new(size_t size)
	{
		// 在成員內存分配函數中使用全局分配函數
		return ::operator new(size);
	}
	void operator delete(void *p)
	{
		// 在成員內存釋放函數中使用全局釋放函數
		::operator delete(p);
	}
};
總結:
1 new T 調用 operator new 進行內存分配, 隨後進行對象的構造。
2 不能對 new 重載覆蓋, 但可以改寫全局的 operator new 進行定製的內存分配,或者定義和爲成員分配函數,同時非常必要對 operator delete 進行改寫。

二 placement new
調用的方法爲:
new(p) T;
p爲已經分配的內存,T爲要進行對象構造的類型,在p內存處進行對象構造,類型爲T。
實質是:
其只有唯一的操作,即在p所指內存進行對象構造,將調用對象構造函數T()。
<new>頭文件提供了在給定內存對對象進行構造的方法這就是:placement new。這是對operator new的重載,其是一個全局函數,不能對其進行改寫,否則視爲重定義。
以下代碼示例自定義內存分配函數並且調用placement new進行自己的對象構造,其實就是代替了new創建對象的兩個步驟
/// Create time: 2014-7-29 09:14:39 By ldlan
/// C++, VS2010
#include <iostream>
using namespace std;

// 自定義的內存分配函數
void* operator new(size_t size)
{
	void* p = malloc(size);
	return p;
}
// 自定義的內存釋放函數
void operator delete(void *p)
{
	free(p);
}

class Time
{
private:
	int year, month, day;
public:
	Time():year(1970),month(1),day(1){}
	~Time(){
	}
	// 成員內存分配函數,內部調用全局的內存分配函數就是,這也是我們自定義的,全局內存分配函數已經被我們改寫覆蓋
	void* operator new(size_t size)
	{
		return ::operator new(size);
	}
	// 成員內存釋放函數
	void operator delete(void *p)
	{
		::operator delete(p);
	}
};


int main(void)
{
	// 以下兩個步驟就是new創建對象的代替
	//(1)調用成員內存分配函數,而實際上調用到了我們改寫的全局內存分配函數
	// 實際上就是 void* today = malloc(sizeof(Time));
	void *today = operator new(sizeof(Time));

	//(2)調用在placement new, 在today所指內存處進行對象構造,即調用構造函數Time()
	::new(today) Time;  // ::爲了調用全局的 placement new

	// 更完善的這裏應該調用對象的析構函數,operator delete僅進行內存的釋放
	operator delete(today);
	return 0;
}
如果企圖將 placement new 定義爲類成員時,實際是對成員 operator new 的重載,與全局的 placement 是不同的兩個函數,其並沒有實現對象的構造過程。
/// Create time: 2014-7-29 09:14:39 By ldlan
/// C++, VS2010
#include <iostream>

using namespace std;

void* operator new(size_t size)
{
	void* p = malloc(size);
	return p;
}
void operator delete(void *p)
{
	free(p);
}


class Time
{
private:
	int year, month, day;
public:
	Time():year(1970),month(1),day(1){}
	~Time(){
	}
	void* operator new(size_t size)
	{
		return ::operator new(size);
	}
	void operator delete(void *p)
	{
		::operator delete(p);
	}
	/// 期望定義成員placement new, 實際是成員operator new 的重載,並沒有進行對象構造
	void* operator new(size_t size, void *p)
	{
		return p;
	}
};


int main(void)
{
	// 內存分配
	void *today = operator new(sizeof(Time));
	// 缺少對象構造
	new(today) Time;  // 沒有::

	operator delete(today);
	return 0;
}
總結:
1 placement new 專門在指定內存進行對象的構造, 全局 placement new: void* operator new(size_t size, void *p)不可以改寫,調用該函數會造成構造函數的調用, 要保證 p 進行了內存分配。

三 可以對 operator new 進行重載
形式爲
void* operator new(size_t size, T *p, ...)
void* operator delete(void*, T *p, ...)
等等。
發佈了49 篇原創文章 · 獲贊 6 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章