這一部分會將要討論一下auto_ptr.c++標(biāo)準(zhǔn)庫提供auto_ptr作為一種智能指針,有了這種智能指針,就可以在異常被拋出的時候避免資源的泄漏.注意,auto_ptr只是智能指針的一種.因為事實上有多種智能指針存在.而auto_ptr只是被用來滿足某種情形下的需求的.而對于其他一些情形,auto_ptr無能為力.所以在使用的時候 要格外注意.
auto_ptr的動機(jī) 通常,一個函數(shù)會按照下面的流程進(jìn)行操作:
1.獲取資源.
2.進(jìn)行一些操作.
3.釋放之前所獲取的資源.
如果函數(shù)所獲取的那些資源與本地對象綁定,它們就會在函數(shù)結(jié)束的時候被自動釋放掉.因為本地對象的析構(gòu)函數(shù)會被調(diào)用.但是如果資源被顯式獲取,并且沒有與任何對象綁定,它們必須也被顯式的釋放掉.在使用指針的時候,資源通常是被顯式管理的.
一種典型的像上面這樣使用資源的方式就是使用new來創(chuàng)建和用delete來釋放.
但是作釋放用的delete操作往往被忽略(特別是函數(shù)有返回值的時候).當(dāng)然,出現(xiàn)異常的時候,也同樣會發(fā)生這種風(fēng)險.因為異常有可能馬上停止你函數(shù)的執(zhí)行,而不去進(jìn)行delete釋放.結(jié)果就是內(nèi)存泄漏,或者說得寬泛一些,是"資源泄漏".為了避免資源泄漏,通常需要函數(shù)能夠捕獲所有的異常.隨之而來的就是,代碼變得越來越復(fù)雜,冗長.
伴隨著這種情況的發(fā)生,一種智能指針auto_ptr出現(xiàn)了.在任何時候,一旦指針本身被銷毀,它所指向的數(shù)據(jù)也會被銷毀.此外,因為智能指針是一個本地變量,不管函數(shù)到底是因為正常結(jié)束,還是因為非正常結(jié)束,auto_ptr所指向的數(shù)據(jù)都會被銷毀.
有了auto_ptr,delete語句和catch語句就變得不那么必要了.auto_ptr和普通指針的使用方式基本相同,即用樣用"*"表示它所指向的對象,同樣用"->"來訪問所指向?qū)ο蟮某蓡T方法.但是有關(guān)指針的運(yùn)算(比如指針的自加)不被支持(這也許是一個優(yōu)點,因為指針運(yùn)算也許會造成一些麻煩).
注意auto_ptr<>不允許你使用指派的方式來聲明它所指向的對象,比如:
下面的操作是不允許的:
std::auto_ptr<ClassA> ptr2 = new ClassA; //ERROR
而應(yīng)該采用顯式的構(gòu)造函數(shù)來初始化:
std::auto_ptr<ClassA> ptr1(new ClassA); //OK
通過auto_ptr來轉(zhuǎn)換所有權(quán) auto_ptr在語意上提供了對于所有全的嚴(yán)格約束.這意味著因為如果一個auto_ptr刪除了它所指向的對象,那么這個對象將不會被其他任何對象所擁有.兩個或以上的auto_ptr絕不能同時擁有一個對象.不幸的是,這種情況是有可能出現(xiàn)的.所以只能有程序員來確保這種情況不會發(fā)生.
那么在這種情況下,auto_ptr的拷貝構(gòu)造函數(shù)如何工作呢?通常它會把一個對象的數(shù)據(jù)復(fù)制給另外一個對象,但是在這里,恰恰是這種行為會導(dǎo)致兩個auto_ptr擁有相同對象這種情況的出現(xiàn).解決方法很簡單,但是卻得出了一個重要結(jié)論:auto_ptr的拷貝構(gòu)造函數(shù)和指派操作促成了auto_ptr對于對象所有權(quán)的一次移交.
看一下下面的代碼:
//initialize an auto_ptr with a new object
std::auto_ptr<ClassA> ptr1(new ClassA);
//copy the auto_ptr
//- transfers ownership from ptr1 to ptr2
std::auto_ptr<ClassA> ptr2(ptr1);
第一句中,ptr1擁有new所創(chuàng)建的那個對象.然后第二句把對于對象的所有權(quán)從ptr1轉(zhuǎn)移給了ptr2.所以在第二句之后,ptr2擁有new創(chuàng)建的那個對象的所有權(quán),而ptr1則自動失去了對于那個對象的所有權(quán).ClassA只會在ptr2被析構(gòu)的時候被釋放掉.
同樣,對于一次指派操作也是如此.如下所示:
//initialize an auto_ptr with a new object
std::auto_ptr<ClassA> ptr1(new ClassA);
std::auto_ptr<ClassA> ptr2; //create another auto_ptr
ptr2 = ptr1; //assign the auto_ptr
//- transfers ownership from ptr1 to ptr2
注意,隨著所有權(quán)的移交,之前失去對象所有權(quán)的那個auto_ptr就變成了一個空指針.
當(dāng)然,還可以讓這個失去所指的空指針重新指向一個對象,像下面這樣:
std::auto_ptr<ClassA> ptr; //create an auto_ptr
ptr = std::auto_ptr<ClassA>(new ClassA); //OK, delete old object and own new
對于所指向的對象的所有權(quán)的變換為我們提供了auto_ptr的一種潛在用法.函數(shù)可以使用向其他的函數(shù)傳遞所有權(quán).這包含兩種情況.
1.傳入函數(shù)的對象不再使用.即在auto_ptr作為參數(shù)傳遞的時候.在這種情況下,被調(diào)用的函數(shù)得到了傳入的auto_ptr所指向的那個對象的所有權(quán).因此,如果函數(shù)不再將對象的所有權(quán)轉(zhuǎn)移出來,那么對象就會在函數(shù)的調(diào)用結(jié)束之后銷毀.
2.函數(shù)要向外傳出對象.當(dāng)auto_ptr被返回的時候,所有權(quán)由被調(diào)用的函數(shù)轉(zhuǎn)移給調(diào)用方.
由于auto_ptr總是牽扯到對象所有權(quán)變換的問題,所以在使用的時候一定要注意你是否真的要轉(zhuǎn)換這個所有權(quán).
你可能打算通過引用傳遞auto_ptr(s).但是這樣做有可能最終你都不清楚所有權(quán)的歸屬了.總之,這不是一個好的決定或設(shè)計.
從auto_ptr的概念出發(fā),你可能會覺得即使是傳遞常指針的話,對象的歸屬也會改變.如果這種情況可能發(fā)生,那將是非常危險的.因為人們總是不期待一個成為"常量"的東西發(fā)生改變.幸運(yùn)的是,通過一些技術(shù)上的處理,這樣做是不可能的.如:
1 #include<iostream>
2 using namespace std;
3 int getValue(auto_ptr<int>);
4 int main()
5 {
6 const auto_ptr<int> myAutoPtr=auto_ptr<int>(new int);
7 *myAutoPtr=10;
8 cout<<getValue(myAutoPtr)<<endl;
9
10 }
11 int getValue(auto_ptr<int> ptr)
12 {
13 return 10*(*ptr);
14 }
上面首先定義了常量的auto_ptr,這就表明,這個auto_ptr不能將自己所指對象的所有權(quán)傳遞給其他對象.因而調(diào)用函數(shù)getValue的時候如果傳遞了上面定義的auto_ptr,就會被編譯器發(fā)現(xiàn),并作為編譯錯誤反饋回來:
錯誤: passing ‘const std::auto_ptr<int>’ as ‘this’ argument of ‘std::auto_ptr<_Tp>::operator std::auto_ptr_ref<_Tp1>() [with _Tp1 = int, _Tp = int]’ discards qualifiers
將auto_ptr(s)作為成員變量
當(dāng)然,如果在類中使用auto_ptr的時候,你同樣也可以避免資源泄漏這種問題的發(fā)生.如果你使用auto_ptr取代通常的指針的話,你將不再需要對那些對象進(jìn)行手動的析構(gòu)處理.同時,auto_ptr也能夠有效避免因為初始化異常而導(dǎo)致資源泄漏這種情況的發(fā)生.因為析構(gòu)總是在構(gòu)造之后,所以如果在構(gòu)造的時候發(fā)生異常,你往往不能夠及時釋放資源,進(jìn)而導(dǎo)致資源泄漏情況的發(fā)生.
但是,在享用了auto_ptr帶來的諸多好處的同時,你在處理拷貝構(gòu)造函數(shù)和重載賦值操作的時候,要格外注意auto_ptr所有權(quán)變換的問題.當(dāng)然,避免這類問題的最好方法就是使用常量指針.
有關(guān)auto_ptr(s)的濫用 auto_ptr能夠滿足一些需要,特別是容易發(fā)生資源泄漏的時候,它總能夠發(fā)揮好的效果.但是在使用它的時候仍然需要注意,不要濫用.在使用的時候,要注意以下幾點:
1.auto_ptr(s)不能夠共享對于所指向?qū)ο蟮乃袡?quán).
2auto_ptr(s)不提供對于數(shù)組的支持.因為在釋放資源的時候,auto_ptr使用的是delete而不是delete[].當(dāng)然,對于數(shù)組而言,STL也有相應(yīng)的處理辦法,比如容器.
3.auto_ptr(s)不是智能指針的全部.注意它并不能解決一切問題.注意它的應(yīng)用場景.
4.auto_ptr(s)不能滿足容器中對象的操作要求.
posted on 2007-07-12 22:46
littlegai 閱讀(358)
評論(0) 編輯 收藏 引用 所屬分類:
我的讀書筆記