智能指针——auto_ptr
1. 開篇
C++里面的四個智能指針:auto_ptr、unique_ptr、shared_ptr、weak_ptr,其中后三個是C++11支持,而這個auto_ptr已經被C++11棄用。但auto_ptr還是有必要學習的。C++的auto_ptr所做的事情,就是動態分配對象以及當對象不在需要時自動執行清理。
2. 構造函數與析構函數
auto_ptr在構造時獲取對某個對象的所有權(ownership),在析構時釋放該對象。我們可以這樣使用auto_ptr來提高代碼安全性:
int*p = new int(0); auto_ptr<int> ap(p);從此我們不必關心應該何時釋放p,也不用擔心發生異常會有內存泄漏。
注意:
(1) 因為auto_ptr析構的時候肯定會刪除他所擁有的那個對象,所以我們就要注意了,一個蘿卜一個坑,兩個auto_ptr不能同時擁有同一個對象。像這樣:
因為ap1與ap2都認為指針p是歸它管的,在析構時都試圖刪除p,兩次刪除同一個對象的行為在C++標準中是未定義的。所以我們必須防止這樣使用auto_ptr。
(2) 下面這種用法:
String *sar = new String[10]; auto_ptr<String> ap(sar);因為auto_ptr的析構函數中刪除指針用的是delete,而不是delete[],所以我們不應該用auto_ptr來管理一個數組指針。
(3) 構造函數的explicit關鍵詞有效阻止從一個"裸"指針隱式轉換成auto_ptr類型。
3. 拷貝構造與賦值
與引用計數型智能指針不同的,auto_ptr要求其對"裸"指針的完全占有性。也就是說一個"裸"指針不能同時被兩個以上的auto_ptr所擁有。那么,在拷貝構造或賦值操作時,我們必須作特殊的處理來保證這個特性。 auto_ptr的做法是"所有權轉移" ,即拷貝或賦值的源對象將失去對"裸"指針的所有權,所以,與一般拷貝構造函數,賦值函數不同,auto_ptr的拷貝構造函數,賦值函數的參數為引用而不是常引用(const reference)。當然,一個auto_ptr也不能同時擁有兩個以上的"裸"指針,所以,拷貝或賦值的目標對象將先釋放其原來所擁有的對象。
注意:
(1) 因為一個auto_ptr被拷貝或被賦值后,其已經失去對原對象的所有權,這個時候,對這個auto_ptr的提領(dereference)操作是不安全的。
如下:
這種情況較為隱蔽的情形出現在將auto_ptr作為函數參數按值傳遞,因為在函數調用過程中在函數的作用域中會產生一個局部對象來接收傳入的auto_ptr(拷貝構造),這樣,傳入的實參auto_ptr就失去了其對原對象的所有權,而該對象會在函數退出時被局部auto_ptr刪除。
如下:
因為這種情況太隱蔽,太容易出錯了,所以auto_ptr作為函數參數按值傳遞是一定要避免的。或許大家會想到用auto_ptr的指針或引用作為函數參數或許可以,但是仔細想想,我們并不知道在函數中對傳入的auto_ptr做了什么,如果當中某些操作使其失去了對對象的所有權,那么這還是可能會導致致命的執行期錯誤。也許用const reference的形式來傳遞auto_ptr會是一個不錯的選擇。
(2) 我們可以看到拷貝構造函數與賦值函數都提供了一個成員模板在不覆蓋“正統"版本的情況下實現auto_ptr的隱式轉換。
如我們有以下兩個類:
那么下列代碼就可以通過,實現從auto_ptr到auto_ptr的隱式轉換,因為Base可以轉換成Object類型。
auto_ptr<object> apobj = auto_ptr<Base>(new Base);(3) 因為auto_ptr不具有值語義(value semantics),所以auto_ptr不能被用在stl標準容器中。
什么是值語義?簡單的說,所有的內置類型〈primitive variables)都具有value semantics。有人也稱它為POD(plain old data),也就是舊時的老數據(有和OOP的新型抽象數據對比之意)。
對一個 具有值語義 的變量賦值可以轉換成內存的bit-wise-copy(按位拷貝)。
什么樣的類沒有值語義呢?我們不妨稱這種型為none-value-semantics type (NVST).
- 有virtual function的類
- 包含NVST成員的類
- NVST的衍生類(derived classed)
- 定義了自己的= operator的類
- 繼承virtual基類的衍生類
很明顯,auto_ptr不符合上述條件,而我們知道stl標準容器要用到大量的拷貝賦值操作,并且假設其操作的類型必須符合以上條件。
4. 提領操作(dereference)
提領擁有兩個操作
一是返回其所擁有的對象的引用
二是實現了通過auto_ptr調用其所擁有的對象的成員。
如:
我們首先要確保這個智能指針確實擁有某個對象,否則,這個操作行為即對空指針的提領是未定義。
5. 輔助函數
(1) get用來顯式的返回auto_ptr所擁有的對象指針。我們可以發現,標準庫提供的auto_ptr既不提供從"裸"指針到auto_ptr的隱式轉換( 構造函數為explicit ),也不提供從auto_ptr到"裸"指針的隱式轉換,從使用上來講可能不那么的靈活,考慮到其所帶來的安全性還是值得的。
(2) release,用來轉移所有權。
(3) reset,用來接收所有權,如果接收所有權的auto_ptr如果已經擁有某對象,必須先釋放該對象。
6. 使用auto_ptr的注意事項
(1) auto_ptr 不能指向數組
(2) auto_ptr 不能共享所有權
(3) auto_ptr 不能通過復制操作來初始化
(4) auto_ptr 不能放入容器中使用
(5) auto_ptr 不能作為容器的成員
(6) 不能把一個原生指針給兩個智能指針對象管理(對所有的智能指針)
總結
以上是生活随笔為你收集整理的智能指针——auto_ptr的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Linux】虚拟地址空间
- 下一篇: 【Linux】库文件