智能指針(auto_ptr) 這個(gè)名字聽(tīng)起來(lái)很酷是不是?其實(shí)auto_ptr 只是C++標(biāo)準(zhǔn)庫(kù)提供的一個(gè)類模板,它與傳統(tǒng)的new/delete控制內(nèi)存相比有一定優(yōu)勢(shì),但也有其局限。本文總結(jié)的8個(gè)問(wèn)題足以涵蓋auto_ptr的大部分內(nèi)容。1. auto_ptr是什么?auto_ptr 是C++標(biāo)準(zhǔn)庫(kù)提供的類模板,auto_ptr對(duì)象通過(guò)初始化指向由new創(chuàng)建的動(dòng)態(tài)內(nèi)存,它是這塊內(nèi)存的擁有者,一塊內(nèi)存不能同時(shí)被分給兩個(gè)擁有者。當(dāng) auto_ptr對(duì)象生命周期結(jié)束時(shí),其析構(gòu)函數(shù)會(huì)將auto_ptr對(duì)象擁有的動(dòng)態(tài)內(nèi)存自動(dòng)釋放。即使發(fā)生異常,通過(guò)異常的棧展開(kāi)過(guò)程也能將動(dòng)態(tài)內(nèi)存釋 放。auto_ptr不支持new 數(shù)組。 2. auto_ptr需要包含的頭文件?#include <memory> 3. 初始化auto_ptr對(duì)象的方法?1) 構(gòu)造函數(shù) 1] 將已存在的指向動(dòng)態(tài)內(nèi)存的普通指針作為參數(shù)來(lái)構(gòu)造 int* p = new int(33); auto_ptr<int> api(p); 2] 直接構(gòu)造智能指針 auto_ptr< int > api( new int( 33 ) ); 2) 拷貝構(gòu)造 利用已經(jīng)存在的智能指針來(lái)構(gòu)造新的智能指針 auto_ptr< string > pstr_auto( new string( "Brontosaurus" ) ); auto_ptr< string > pstr_auto2(
pstr_auto ); 因?yàn)橐粔K動(dòng)態(tài)內(nèi)存智能由一個(gè)智能指針獨(dú)享,所以在拷貝構(gòu)造或賦值時(shí)都會(huì)發(fā)生擁有權(quán)轉(zhuǎn)移的過(guò)程。在此拷貝構(gòu)造過(guò)程中,pstr_auto將失去對(duì)字符串內(nèi)存的所有權(quán),而pstr_auto2將其獲得。對(duì)象銷毀時(shí),pstr_auto2負(fù)責(zé)內(nèi)存的自動(dòng)銷毀。 3) 賦值 利用已經(jīng)存在的智能指針來(lái)構(gòu)造新的智能指針 auto_ptr< int > p1( new int( 1024 ) ); auto_ptr< int > p2( new int( 2048 ) ); p1 = p2; 在賦值之前,由p1 指向的對(duì)象被刪除。賦值之后,p1 擁有int 型對(duì)象的所有權(quán)。該對(duì)象值為2048。 p2 不再被用來(lái)指向該對(duì)象。 4. 空的auto_ptr 需要初始化嗎?通常的指針在定義的時(shí)候若不指向任何對(duì)象,我們用Null給其賦值。對(duì)于智能指針,因?yàn)闃?gòu)造函數(shù)有默認(rèn)值0,我們可以直接定義空的auto_ptr如下: auto_ptr< int >
p_auto_int; 5. 防止兩個(gè)auto_ptr對(duì)象擁有同一個(gè)對(duì)象(一塊內(nèi)存)因?yàn)閍uto_ptr的所有權(quán)獨(dú)有,所以下面的代碼會(huì)造成混亂。 int* p = new int(0); 因?yàn)閍p1與ap2都認(rèn)為指針p是歸它管的,在析構(gòu)時(shí)都試圖刪除p, 兩次刪除同一個(gè)對(duì)象的行為在C++標(biāo)準(zhǔn)中是未定義的。所以我們必須防止這樣使用auto_ptr。 6. 警惕智能指針作為參數(shù)!1) 按值傳遞時(shí),函數(shù)調(diào)用過(guò)程中在函數(shù)的作用域中會(huì)產(chǎn)生一個(gè)局部對(duì)象來(lái)接收傳入的auto_ptr(拷貝構(gòu)造),這樣,傳入的實(shí)參auto_ptr就失去了其對(duì)原對(duì)象的所有權(quán),而該對(duì)象會(huì)在函數(shù)退出時(shí)被局部auto_ptr刪除。如下例: void f(auto_ptr<int> ap) {cout<<*ap;} 2) 引用或指針時(shí),不會(huì)存在上面的拷貝過(guò)程。但我們并不知道在函數(shù)中對(duì)傳入的auto_ptr做了什么,如果當(dāng)中某些操作使其失去了對(duì)對(duì)象的所有權(quán),那么這還是可能會(huì)導(dǎo)致致命的執(zhí)行期錯(cuò)誤。 結(jié)論:const reference是智能指針作為參數(shù)傳遞的底線。 7. auto_ptr不能初始化為指向非動(dòng)態(tài)內(nèi)存原因很簡(jiǎn)單,delete 表達(dá)式會(huì)被應(yīng)用在不是動(dòng)態(tài)分配的指針上這將導(dǎo)致未定義的程序行為。 8. auto_ptr常用的成員函數(shù)1) get() 返回auto_ptr指向的那個(gè)對(duì)象的內(nèi)存地址。如下例: 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 第一行與第三行相同,都是int所在的那塊內(nèi)存的地址。第二行是ap1這個(gè)類對(duì)象本身所在內(nèi)存的地址。 2) reset() 重新設(shè)置auto_ptr指向的對(duì)象。類似于賦值操作,但賦值操作不允許將一個(gè)普通指針指直接賦給auto_ptr,而reset()允許。如下例: auto_ptr< string > pstr_auto( new string( "Brontosaurus" ) ); pstr_auto.reset( new string( "Long -neck" ) ); 在例子中,重置前pstr_auto擁有"Brontosaurus"字符內(nèi)存的所有權(quán),這塊內(nèi)存首先會(huì)被釋放。之后pstr_auto再擁有"Long -neck"字符內(nèi)存的所有權(quán)。 注:reset(0)可以釋放對(duì)象,銷毀內(nèi)存。 3) release() 返回auto_ptr指向的那個(gè)對(duì)象的內(nèi)存地址,并釋放對(duì)這個(gè)對(duì)象的所有權(quán)。 用此函數(shù)初始化auto_ptr時(shí)可以避免兩個(gè)auto_ptr對(duì)象擁有同一個(gè)對(duì)象的情況(與 |
|