您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關(guān)C++ new的面貌有哪些的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考。一起跟隨小編過來看看吧。
1.new的三種面貌
C++中使用new運算符產(chǎn)生一個存在于Heap(堆)上對象時,實際上調(diào)用了operator new()函數(shù)和placement new()函數(shù)。在使用new創(chuàng)建堆對象時,我們要清楚認(rèn)清楚new的三種面貌,分別是:new operator、operator new()和placement new()。
1.1new operator
new operator是C++保留的關(guān)鍵字,我們無法改變其含義,但我們可以改變new完成它功能時調(diào)用的兩個函數(shù),operator new()和placement new()。也就是說我們在使用運算符new時,其最終是通過調(diào)用operator new()和placement new()來完成堆對象的創(chuàng)建工作。使用new operator時,其完成的工作有如下三步:
因此,當(dāng)我們經(jīng)常按照如下方式使用new operator時:
string* sp=new string(“hello world”);
實際上等價于:
//第一步:申請原始空間,行為類似于malloc void* raw=operator new(strlen(“hello world”)); //第二步:通過placement new調(diào)用string類的構(gòu)造函數(shù),初始化申請空間 new (raw) string(“hello world”); //第三部:返回對象指針 string* sp=static_cast<string*>(raw);
1.2operator new()
operator new()用于申請Heap空間,功能類似于C語言的庫函數(shù)malloc(),嘗試從堆上獲取一段內(nèi)存空間,如果成功則直接返回,如果失敗則轉(zhuǎn)而去調(diào)用一個new handler,然后拋出一個bad_alloc異常。operator new()的函數(shù)原型一般為
void* operator new (std::size_t size) throw (std::bad_alloc);
具體實現(xiàn)如下:
void *__CRTDECL operator new(size_t size) throw (std::bad_alloc) { // try to allocate size bytes void *p; while ((p = malloc(size)) == 0) //申請空間 if (_callnewh(size) == 0) //若申請失敗則調(diào)用處理函數(shù) { // report no memory static const std::bad_alloc nomem; _RAISE(nomem); //#define _RAISE(x) ::std:: _Throw(x) 拋出nomem的異常 } return (p); }
注意:
(1)函數(shù)后添加throw表示可能會拋出throw后括號內(nèi)的異常;
(2)operator new()分為全局和類成員。當(dāng)為類成員函數(shù)時,使用new產(chǎn)生類對象時調(diào)用的則是其成員函數(shù)operator new()。如果要重載全局的operator new會改變所有默認(rèn)的operator new的方式,所以必須要注意。正如new與delete相互對應(yīng),operator new與operator delete也是一一對應(yīng),如果重載了operator new,那么理應(yīng)重載operator delete。
placement new():
一般來說,使用new申請空間時,是從系統(tǒng)的堆中分配空間,申請所得空間的位置根據(jù)當(dāng)時內(nèi)存實際使用情況決定。但是,在某些特殊情況下,可能需要在程序員指定的特定內(nèi)存創(chuàng)建對象,這就是所謂的“定位放置new”(placement new)操作。placement new()是一個特殊的operator new(),因為其是operator new()函數(shù)的重載版本,只是取了個別名叫作placement new罷了。作用是在已經(jīng)獲得的堆空間上調(diào)用類構(gòu)造函數(shù)來初始化對象,也就是定位構(gòu)造對象。通常情況下,構(gòu)造函數(shù)是由編譯器自動調(diào)用的,但是不排除程序員手動調(diào)用的可能性,比如對一塊未初始化的內(nèi)存進行處理,獲得想要的對象,這是需要求助于placement new()。placement new()是C++標(biāo)準(zhǔn)庫的一部分,被申明在頭文件<new>中,其函數(shù)原型是:
void* operator new(std::size_t, void* __p);
具體實現(xiàn)如下:
void* operator new(std::size_t, void* __p) throw() { return __p; }
注意:
(1)placement new()的函數(shù)原型不是void* placement new(std::size_t, void* __p)
;
(2)placement new只是operator new()的一個重載,多了一個已經(jīng)申請好的空間,由void* __p指定;
(3)用法是new (addr) constructor()
,對addr指定的內(nèi)存空間調(diào)用構(gòu)造函數(shù)進行初始化。為何稱為placement new,從其用法可以看出只是用于調(diào)用構(gòu)造函數(shù)。
定位放置new操作的語法形式不同于普通的new操作。例如,一般都用如下語句A* p=new A;申請空間,而定位放置new操作則使用如下語句A* p=new (ptr) A;申請空間,其中ptr就是程序員指定的內(nèi)存首地址??疾烊缦鲁绦颉?/p>
#include <iostream> using namespace std; 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[100]; mem[0]='A'; mem[1]='\0'; mem[2]='\0'; mem[3]='\0'; cout<<(void*)mem<<endl; A* p=new (mem) A; cout<<p<<endl; p->show(); p->~A(); getchar(); }
程序運行結(jié)果:
0024F924
A's constructor
0024F924
num:65
~A
閱讀以上程序,注意以下幾點。
(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的構(gòu)造函數(shù),但是由于對象的空間不會自動釋放(對象實際上是借用別人的空間),所以必須顯示的調(diào)用類的析構(gòu)函數(shù),如本例中的p->~A()。
(4)萬不得已才使用placement new,只有當(dāng)你真的在意對象在內(nèi)存中的特定位置時才使用它。例如,你的硬件有一個內(nèi)存映像的I/O記時器設(shè)備,并且你想放置一個Clock對象在哪那個位置。
總結(jié):
(1)若想在堆上建立一個對象,應(yīng)該用new操作符。它既分配內(nèi)存又調(diào)用其構(gòu)造函數(shù)進行初始化。
(2)若僅僅想分配內(nèi)存,應(yīng)該調(diào)用operator new(),他不會調(diào)用構(gòu)造函數(shù)。若想定制自己在堆對象被建立時的內(nèi)存分配過程,應(yīng)該重寫自己的operator new()。
(3)若想在一塊已經(jīng)獲得的內(nèi)存空間上建立一個對象,應(yīng)該用placement new。雖然在實際開發(fā)過程中,很少需要重寫operator new(),使用內(nèi)置的operator new()即可完成大部分程序所需的功能。但知道這些,有助于一個C++程序猿對C++內(nèi)存的管理有個清楚的認(rèn)識。
2.了解delete和operator delete()
為了避免內(nèi)存泄漏,每個動態(tài)內(nèi)存分配必須與一個等同相反的 deallocation 對應(yīng)。數(shù)operator delete與delete操作符的關(guān)系與operator new與new操作符是一樣的。delete用于使用使用new申請的空間,operator delete用于釋放operator new申請的空間(類似于malloc與free),那誰來清理placement new初始化的內(nèi)存內(nèi)容呢?唯一辦法就是調(diào)用對象的析構(gòu)函數(shù)。
示例代碼:
string* sp=new string(“hello world”); delete sp;
第一行代碼在上文已經(jīng)剖析,那么當(dāng)調(diào)用delete sp時,發(fā)生了什么?
delete sp等價于:
ps->~string(); //用于清理內(nèi)存內(nèi)容,對應(yīng)placement new operator delete(ps);//釋放內(nèi)存空間,對應(yīng)于operator new()
其中operator delete()的函數(shù)原型為:
void operator delete(void *memoryToBeDeallocated);
感謝各位的閱讀!關(guān)于C++ new的面貌有哪些就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。