智能指針

auto_ptr

auto_ptr在構造時獲取對某個對象的所有權(ownership),在析構時釋放該對象。

1) 因爲auto_ptr析構的時候肯定會刪除他所擁有的那個對象,所以我們就要注意了,一個蘿蔔一個坑,兩個auto_ptr不能同時擁有同一個對象。像這樣:
1
2
3
int*p=new int(0);
auto_ptr<int>ap1(p);
auto_ptr<int>ap2(p);

因爲ap1與ap2都認爲指針p是歸它管的,在析構時都試圖刪除p, 兩次刪除同一個對象的行爲在C++標準中是未定義的。


2) 智能指針不能指向數組指針:
1
2
int*pa=new int[10];
auto_ptr<int>ap(pa);
因爲auto_ptr的析構函數中刪除指針用的是delete,而不是delete [],所以我們不應該用auto_ptr來管理一個數組指針。


3) 構造函數的explicit關鍵詞有效阻止從一個“裸”指針隱式轉換成auto_ptr類型。


引用計數智能指針不同的,auto_ptr要求其對“裸”指針的完全佔有性。也就是說一個“裸”指針不能同時被兩個以上的auto_ptr所擁有。那麼,在拷貝構造或賦值操作時,我們必須作特殊的處理來保證這個特性。auto_ptr的做法是“所有權轉移”,即拷貝或賦值的源對象將失去對“裸”指針的所有權,所以,與一般拷貝構造函數賦值函數不同, auto_ptr的拷貝構造函數,賦值函數的參數爲引用而不是常引用(const reference).當然,一個auto_ptr也不能同時擁有兩個以上的“裸”指針,所以,拷貝或賦值的目標對象將先釋放其原來所擁有的對象。
這裏的注意點是:
1) 因爲一個auto_ptr被拷貝或被賦值後, 其已經失去對原對象的所有權,這個時候,對這個auto_ptr的提領(dereference)操作是不安全的。如下:
1
2
3
4
int*p=new int(0);
auto_ptr<int>ap1(p);
auto_ptr<int>ap2=ap1;
cout<<*ap1;//錯誤,此時ap1只剩一個null指針在手了
這種情況較爲隱蔽的情形出現在將auto_ptr作爲函數參數按值傳遞,因爲在函數調用過程中在函數的作用域中會產生一個局部對象來接收傳入的auto_ptr(拷貝構造),這樣,傳入的實參auto_ptr就失去了其對原對象的所有權,而該對象會在函數退出時被局部auto_ptr刪除。如下:
1
2
3
4
5
6
7
8
void f(auto_ptr<int>ap)
{
    cout<<*ap;
}
 
auto_ptr<int>ap1(new int(0));
f(ap1);
cout<<*ap1;//錯誤,經過f(ap1)函數調用,ap1已經不再擁有任何對象了。
因爲這種情況太隱蔽,太容易出錯了, 所以auto_ptr作爲函數參數按值傳遞是一定要避免的。或許大家會想到用auto_ptr的指針或引用作爲函數參數或許可以,但是仔細想想,我們並不知道在函數中對傳入的auto_ptr做了什麼, 如果當中某些操作使其失去了對對象的所有權, 那麼這還是可能會導致致命的執行期錯誤。 也許,用const reference的形式來傳遞auto_ptr會是一個不錯的選擇。

2)我們可以看到拷貝構造函數與賦值函數都提供了一個成員模板在不覆蓋“正統”版本的情況下實現auto_ptr的隱式轉換。如我們有以下兩個類
1
2
class base{};
class derived:public base{};
那麼下列代碼就可以通過,實現從auto_ptr<derived>到auto_ptr<base>的隱式轉換,因爲derived*可以轉換成base*類型
1
auto_ptr<base>apbase=auto_ptr<derived>(new derived);
3) 因爲auto_ptr不具有值語義(value semantic), 所以auto_ptr不能被用在stl標準容器中。
所謂值語義,是指符合以下條件的類型(假設有類A):
1
2
3
4
5
6
A a1;
A a2(a1);
A a3;
a3=a1;
//那麼
a2==a1,a3==a1
很明顯,auto_ptr不符合上述條件,而我們知道stl標準容器要用到大量的拷貝賦值操作,並且假設其操作的類型必須符合以上條件。

4 輔助函數
1) get用來顯式的返回auto_ptr所擁有的對象指針。我們可以發現,標準庫提供的auto_ptr既不提供從“裸”指針到auto_ptr的隱式轉換(構造函數爲explicit),也不提供從auto_ptr到“裸”指針的隱式轉換,從使用上來講可能不那麼的靈活, 考慮到其所帶來的安全性還是值得的。
2) release,用來轉移所有權
3) reset,用來接收所有權,如果接收所有權的auto_ptr如果已經擁有某對象,必須先釋放該對象。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章