C++中的opeartor?new和placement?new使用步驟
new做了哪些:
在c++中,對(duì)new的調(diào)用時(shí),new完成的工作通常是有以下幾步:
調(diào)用operator new函數(shù)分配出內(nèi)存待用對(duì)象的構(gòu)造方法構(gòu)造出對(duì)象返回該對(duì)象的指針
operator new
(1)只分配所要求的空間,不調(diào)用相關(guān)對(duì)象的構(gòu)造函數(shù)。當(dāng)無(wú)法滿(mǎn)足所要求分配的空間時(shí),則
->如果有new_handler,則調(diào)用new_handler,否則
->如果沒(méi)要求不拋出異常(以nothrow參數(shù)表達(dá)),則執(zhí)行bad_alloc異常,否則
->返回0
(2)可以被重載
(3)重載時(shí),返回類(lèi)型必須聲明為void*
(4)重載時(shí),第一個(gè)參數(shù)類(lèi)型必須為表達(dá)要求分配空間的大?。ㄗ止?jié)),類(lèi)型為size_t
(5)重載時(shí),可以帶其它參數(shù)
opeartor new重載測(cè)試
class X
{
public:
X() { cout<<"constructor of X"<<endl;}
~X() { cout<<"destructor of X"<<endl;}
void* operator new(size_t size,string str)
{
cout<<"operator new size "<<size<<" with string "<<str<<endl;
return ::operator new(size);
}
void operator delete(void* pointee)
{
cout<<"operator delete"<<endl;
::operator delete(pointee); //調(diào)用全局的 operator delete函數(shù)
}
private:
int num;
};
int main()
{
X *px = new("A new") X;
delete px;
return 0;
}
// 輸出結(jié)果
// operator new size 4 with string A new
// constructor of X
// destructor of X
// operator delete
那么為什么要重載operator new函數(shù)呢?首先第一點(diǎn)當(dāng)然是因?yàn)閚ew作為一種操作符是不能被重載的,而作為new中重要的一環(huán):分配內(nèi)存,重載operatir new就變的一種必要的操作了。全局opeartor new在分配內(nèi)存時(shí),實(shí)際上也是對(duì)malloc的一層包裝,在進(jìn)行大量次數(shù)的內(nèi)存分配時(shí)容易出現(xiàn)內(nèi)存碎片的問(wèn)題,通過(guò)重載operator new函數(shù)可以自定的將內(nèi)存分配在獨(dú)立出來(lái)的一塊內(nèi)存區(qū)域,可以更高效率的實(shí)現(xiàn)內(nèi)存分配的管理,同時(shí)也可以有效減少內(nèi)存碎片化以及不易與管理的問(wèn)題。
重載operator new函數(shù)還有很多的用途,比如,他可以幫助我們查找內(nèi)存泄漏,在c++中,內(nèi)存泄漏是痛中之痛,重載該函數(shù)并與宏定義相配合可以很好的檢測(cè)出內(nèi)存泄漏的地方在哪里。相關(guān)文章鏈接:http://www.dbjr.com.cn/article/41939.htm
placement new
placement new是operator new的一個(gè)重載版本,他的作用是可以將一個(gè)對(duì)象分配到指定的內(nèi)存空間。實(shí)現(xiàn)代碼如下:
void* operator new(std::size_t, void* __p) throw()
{
return __p;
}
placement new 只是operator new的一個(gè)重載版本,只是起了一個(gè)別名而已.
代碼示例:
class A{
int num;
public:
A(){
cout<<"A's constructor"<<endl;
}
~A(){
cout<<"~A"<<endl;
}
void show(){
cout<<"num:"<<num<<endl;
}
};
int main()
{
char* mem;
cout << (void*)mem << endl;
A* a = new(mem) A;
cout << (void*)a << endl;
return 0;
}
// 0x104e570ac
// A's constructor
// 0x104e570ac
閱讀以上程序,注意以下幾點(diǎn)。
(1)用定位放置new操作,既可以在棧(stack)上生成對(duì)象,也可以在堆(heap)上生成對(duì)象。如本例就是在棧上生成一個(gè)對(duì)象。
(2)使用語(yǔ)句A* p=new (mem) A;定位生成對(duì)象時(shí),指針p和數(shù)組名mem指向同一片存儲(chǔ)區(qū)。所以,與其說(shuō)定位放置new操作是申請(qǐng)空間,還不如說(shuō)是利用已經(jīng)請(qǐng)好的空間,真正的申請(qǐng)空間的工作是在此之前完成的。
(3)使用語(yǔ)句A *p=new (mem) A;定位生成對(duì)象是,會(huì)自動(dòng)調(diào)用類(lèi)A的構(gòu)造函數(shù),但是由于對(duì)象的空間不會(huì)自動(dòng)釋放(對(duì)象實(shí)際上是借用別人的空間),所以必須顯示的調(diào)用類(lèi)的析構(gòu)函數(shù),如本例中的p->~A()。
(4)萬(wàn)不得已才使用placement new,只有當(dāng)你真的在意對(duì)象在內(nèi)存中的特定位置時(shí)才使用它。例如,你的硬件有一個(gè)內(nèi)存映像的I/O記時(shí)器設(shè)備,并且你想放置一個(gè)Clock對(duì)象在哪那個(gè)位置。
在一些高效率的程序中,往往會(huì)開(kāi)辟出一塊獨(dú)立的內(nèi)存空間配合placement new來(lái)實(shí)現(xiàn)高效率的內(nèi)存釋放與配置,如在SGI STL的內(nèi)存配置函數(shù)allocate 與 deallcate函數(shù),以及大名鼎鼎的memory pool技術(shù)都很大程度上依靠了placement new定位創(chuàng)建對(duì)象。在快速的內(nèi)存分配與釋放的過(guò)程中這是一個(gè)非常實(shí)用的方法。
Placement new使用步驟
在很多情況下,placement new的使用方法和其他普通的new有所不同。這里提供了它的使用步驟。
第一步 緩存提前分配
有三種方式:
1.為了保證通過(guò)placement new使用的緩存區(qū)的memory alignment(內(nèi)存隊(duì)列)正確準(zhǔn)備,使用普通的new來(lái)分配它:在堆上進(jìn)行分配
class Task ; char * buff = new [sizeof(Task)]; //分配內(nèi)存 (請(qǐng)注意auto或者static內(nèi)存并非都正確地為每一個(gè)對(duì)象類(lèi)型排列,所以,你將不能以placement new使用它們。)
2.在棧上進(jìn)行分配
class Task ; char buf[N*sizeof(Task)]; //分配內(nèi)存
3.還有一種方式,就是直接通過(guò)地址來(lái)使用。(必須是有意義的地址)
void* buf = reinterpret_cast<void*> (0xF00F);
第二步:對(duì)象的分配
在剛才已分配的緩存區(qū)調(diào)用placement new來(lái)構(gòu)造一個(gè)對(duì)象。
Task *ptask = new (buf) Task
第三步:使用
按照普通方式使用分配的對(duì)象:
ptask->memberfunction(); ptask-> member; //...
第四步:對(duì)象的析構(gòu)
一旦你使用完這個(gè)對(duì)象,你必須調(diào)用它的析構(gòu)函數(shù)來(lái)毀滅它。按照下面的方式調(diào)用析構(gòu)函數(shù):
ptask->~Task(); //調(diào)用外在的析構(gòu)函數(shù),顯式調(diào)用!
第五步:釋放
你可以反復(fù)利用緩存并給它分配一個(gè)新的對(duì)象(重復(fù)步驟2,3,4)如果你不打算再次使用這個(gè)緩存,你可以象這樣釋放它:
delete [] buf;
總結(jié):
(1)若想在堆上建立一個(gè)對(duì)象,應(yīng)該用new操作符。它既分配內(nèi)存又調(diào)用其構(gòu)造函數(shù)進(jìn)行初始化。
(2)若僅僅想分配內(nèi)存,應(yīng)該調(diào)用operator new(),他不會(huì)調(diào)用構(gòu)造函數(shù)。若想定制自己在堆對(duì)象被建立時(shí)的內(nèi)存分配過(guò)程,應(yīng)該重寫(xiě)自己的operator new()。
(3)若想在一塊已經(jīng)獲得的內(nèi)存空間上建立一個(gè)對(duì)象,應(yīng)該用placement new。在實(shí)際開(kāi)發(fā)過(guò)程中,這種寫(xiě)法一般在高性能高穩(wěn)定場(chǎng)景下使用。本文主要是為了更好的理解STL源碼中alloator的內(nèi)存管理行為所寫(xiě)。
理解可能并不規(guī)范,表達(dá)也會(huì)有所紕漏。
參考文章:
https://cloud.tencent.com/developer/article/1177460
https://blog.51cto.com/u_15060533/4689267
https://www.cnblogs.com/luxiaoxun/archive/2012/08/10/2631812.html
到此這篇關(guān)于C++中的opeartor new和placement new詳解的文章就介紹到這了,更多相關(guān)C++ opeartor new和placement new內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Qt學(xué)習(xí)筆記之QPalette調(diào)色板類(lèi)
這篇文章主要為大家詳細(xì)介紹了Qt學(xué)習(xí)筆記之QPalette調(diào)色板類(lèi),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
C++中調(diào)用復(fù)制(拷貝)函數(shù)的三種情況總結(jié)
這篇文章主要介紹了C++中調(diào)用復(fù)制(拷貝)函數(shù)的三種情況總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
C++實(shí)現(xiàn)模板中的非類(lèi)型參數(shù)的方法
這篇文章主要介紹了C++實(shí)現(xiàn)模板中的非類(lèi)型參數(shù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03

