《More Effective C++》ITEM M9中提到了auto_ptr,說是當異常產生的時候,怎樣釋放為對象分配的堆內存,避免重復編寫內存釋放語句。
PS:這里書里面提到函數退出問題,函數退出會清算棧內存,不論是怎樣正常退出還是異常退出(唯一1種例外就是當你調用 longjmp 時。Longjmp 的這個缺點是 C++率先支持異常處理的主要緣由)。建立在此基礎上我們才把對指針的刪除操作封裝到1個棧對象里面。這樣函數退出(異?;蚴钦#┚蜁{用對象的析構函數,到達我們自動清算所封裝指針指向的內存的目的。
作為新手,不是很理解,記下來,學習學習。
PS:C++11已不提倡用auto_ptr了,請看鏈接:http://www.cplusplus.com/reference/memory/auto_ptr/
Note: This class template is deprecated as of C++11. unique_ptr is
a new facility with a similar functionality, but with improved security (no fake copy assignments), added features (deleters)
and support for arrays. Seeunique_ptr for
additional information.
以下內容copy自:http://blog.sina.com.cn/s/blog_7708265a01010lyv.html
auto_ptr 是C++標準庫提供的類模板,auto_ptr對象通過初始化指向由new創建的動態內存,它是這塊內存的具有者,1塊內存不能同時被分給兩個具有者。當auto_ptr對象生命周期結束時,其析構函數會將auto_ptr對象具有的動態內存自動釋放。即便產生異常,通過異常的棧展開進程也能將動態內存釋放。auto_ptr不支持new 數組。
#include <memory>
1) 構造函數
1] 將已存在的指向動態內存的普通指針作為參數來構造
int* p = new int(33);
auto_ptr<int> api(p);
2] 直接構造智能指針
auto_ptr< int > api( new int( 33 ) );
2) 拷貝構造
利用已存在的智能指針來構造新的智能指針
auto_ptr< string > pstr_auto( new string( "Brontosaurus" ) );
auto_ptr< string > pstr_auto2( pstr_auto );
由于1塊動態內存智能由1個智能指針獨享,所以在拷貝構造或賦值時都會產生具有權轉移的進程。在此拷貝構造進程中,pstr_auto將失去對字符串內存的所有權,而pstr_auto2將其取得。對象燒毀時,pstr_auto2負責內存的自動燒毀。
3) 賦值
利用已存在的智能指針來構造新的智能指針
auto_ptr< int > p1( new int( 1024 ) );
auto_ptr< int > p2( new int( 2048 ) );
p1 = p2;
在賦值之前,由p1 指向的對象被刪除。賦值以后,p1 具有int 型對象的所有權。該對象值為2048。 p2 不再被用來指向該對象。
通常的指針在定義的時候若不指向任何對象,我們用Null給其賦值。對智能指針,由于構造函數有默許值0,我們可以直接定義空的auto_ptr以下:
auto_ptr< int > p_auto_int;
由于auto_ptr的所有權獨有,所以下面的代碼會造成混亂。
int* p = new int(0);
auto_ptr<int> ap1(p);
auto_ptr<int> ap2(p);
由于ap1與ap2都認為指針p是歸它管的,在析構時都試圖刪除p, 兩次刪除同1個對象的行動在C++標準中是未定義的。所以我們必須避免這樣使用auto_ptr。
1) 按值傳遞時,函數調用進程中在函數的作用域中會產生1個局部對象來接收傳入的auto_ptr(拷貝構造),這樣,傳入的實參auto_ptr就失去了其對原對象的所有權,而該對象會在函數退出時被局部auto_ptr刪除。以下例:
void f(auto_ptr<int> ap)
{cout<<*ap;}
auto_ptr<int> ap1(new int(0));
f(ap1);
cout<<*ap1; //毛病,經過f(ap1)函數調用,ap1已不再具有任何對象了。
2) 援用或指針時,不會存在上面的拷貝進程。但我們其實不知道在函數中對傳入的auto_ptr做了甚么,如果當中某些操作使其失去了對對象的所有權,那末這還是可能會致使致命的履行期毛病。
結論:const reference是智能指針作為參數傳遞的底線。
緣由很簡單,delete 表達式會被利用在不是動態分配的指針上這將致使未定義的程序行動。
1) get()
返回auto_ptr指向的那個對象的內存地址。以下例:
int* p = new int(33);
cout << "the adress of p: "<< p << endl;
auto_ptr<int> ap1(p);
cout << "the adress of ap1: " << &ap1 << endl;
cout << "the adress of the object which ap1 point to: " << ap1.get() << endl;
輸出以下:
the adress of p: 00481E00
the adress of ap1: 0012FF68
the adress of the object which ap1 point to: 00481E00
第1行與第3行相同,都是int所在的那塊內存的地址。第2行是ap1這個類對象本身所在內存的地址。
2) reset()
重新設置auto_ptr指向的對象。類似于賦值操作,但賦值操作不允許將1個普通指針指直接賦給auto_ptr,而reset()允許。以下例:
auto_ptr< string > pstr_auto( new string( "Brontosaurus" ) );
pstr_auto.reset( new string( "Long -neck" ) );
在例子中,重置前pstr_auto具有"Brontosaurus"字符內存的所有權,這塊內存首先會被釋放。以后pstr_auto再具有"Long -neck"字符內存的所有權。
注:reset(0)可以釋放對象,燒毀內存。
3) release()
返回auto_ptr指向的那個對象的內存地址,并釋放對這個對象的所有權。
用此函數初始化auto_ptr時可以免兩個auto_ptr對象具有同1個對象的情況(與get函數相比)。
例子以下:
auto_ptr< string > pstr_auto( new string( "Brontosaurus" ) );
auto_ptr< string > pstr_auto2( pstr_auto.get() ); //這是兩個auto_ptr具有同1個對象
auto_ptr< string > pstr_auto2( pstr_auto.release() ); //release可以首先釋放所有權
附上auto_ptr的實現代碼: