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