new/delete是c++中動態構造對象的表達式 ,一般情況下的new/delete都是指的new/delete表達式,這是一個操作符,和sizeof一樣,不能改變其意義。
new/delete表達式的聲明如下:
::(optional)
除了全局作用符::和初始化參數,還有個 placement_params,這是不常見的,要理解這個參數的作用,就要了解operator new和placement new。
眾所周知,new表達式做了兩個工作:1.分配內存;2.在分配的內存上調用構造函數構造對象。比如我們分配一個string對象
string *str = new string(“Kian”);
編譯器首先調用operator new分配一塊內存,類似於malloc,然後在mem上面調用構造函數,
1.void *mem = operator new(sizeof(string));
2. create string at men.
第二步我們是控制不了的,但是operator new卻是可以修改的。
Operator new/delete的聲明如下:
* * ( std::size_t count, std::nothrow_t& delete ( * delete ( * ptr, std::nothrow_t& tag);
第二種帶參數tag的聲明稱為nothrow形式,因為現在的operator new如果分配內存失敗的話會拋出bad_alloc異常. 有時候我們不想拋出異常,而是根據返回值判斷內存分配失敗與否,nothrow形式就是這個作用,失敗時不拋出異常,而是返回null指針。
我們可以直接重載operator new, 定制自己的內存分配策略,常見的作用是優化內存使用性能。重載operator new不需要看見聲明就可以直接使用。我們重定義一個簡單的版本:
* delete( * *i = ( *str = std::(
運行結果:
operator new called, size=4
operator delete called
operator new called, size=4
operator new called, size=17
operator delete called
operator delete called
可是有時候我們希望擁有更多的功能,比如記錄內存分配釋放的位置,用於檢測內存錯誤,或者直接在已有的內存上構造對象,那麼必須定義更多參數,這就需要placement new/delete,聲明如下.
* ( std::size_t count, ** ( std::size_t count, user-defined- delete ( * ptr, * delete ( * ptr, user-defined-args...);
可以直接在已有內存上構造對象:
*mem = (*)malloc(( *j = (mem) (,mem, j, *
運行結果:
mem=0x8a48008, j=0x8a48008, *j = 3
可以看出new直接在mem上面構造了對象。
目前,void* operator new ( std::size_t count, void* ptr )在全局域還不能被重載,但是void* operator new ( std::size_t count, user-defined-args... )可以自由定義。
比如記錄內存分配發生的位置:
* delete( ** (std::size_t size, * filename, :: delete( *place, * filename, *k = (__FILE__, __LINE__) (, k, *
運行結果:
new called at testnew.cpp:41 size=4
operator new called, size=4
k=0x847f008 *k=1
operator delete called
在每個new中打印了文件名和行號,不過細心的你會發現delete時並沒有調用重載的placement delete ,這個delete只有在構造對象時拋出了異常才會調用,我們寫一個簡單的class來看看:
v):value_(v){ *= (__FILE__, __LINE__) ThrowExcept(( &
運行結果:
new called at testnew.cpp:53 size=4
operator new called, size=4
delete called at testnew.cpp:53 place=0x9e2e008
operator delete called
catch exception 1
自定義的delete被正常調用,這麼做的原因在於如果構造函數拋出異常,系統正常的operator delete並不知道用戶自定義的placement new做了什麼,自然也不知道怎麼去釋放。所以如果自己定義placement new, 一定要定義對應的palcement delete,不然可能出現memory leak。
http://en.cppreference.com/w/cpp/memory/new/operator_new
http://en.cppreference.com/w/cpp/language/new
《effective/more effective c++》