作者:winterTTr(轉載請註明) 資料來源:《STL標準庫》
爲什麼說它神祕呢,那好吧,我可以換一個更直白的詞語,那就是“陷阱重重”。
對於不瞭解auto_ptr的人來說,使用它就是一種災難,而避免這種災難,就必須揭開它神祕的面紗,瞭解其內部運作機制。
- 爲什麼要出現auto_ptr
看這樣一段代碼,如果中間的操作出現異常,或者出現return,我們將會忘記釋放ptr這個變量的空間,這無疑會造成內存泄露。而這種泄露往往可能是我們不經意的。那麼,auto_ptr的出現,就是爲了解決這種問題而出現的。他利用局部變量離開作用域會釋放的原則,將主動申請的資源指針放置於其內部,並在其析構的時候,釋放掉資源。由於auto_ptr本身是局部變量,就保證了主動申請的資源能夠在離開作用域的時候被及時合理的釋放。同時,即便是異常的出現,也不會造成內存的泄露。
好, 我們重寫上面的代碼:
當然,auto_ptr重載了*和->操作符,我們能像正常使用原始指針一樣,去使用這個變量。
使用的注意點:
1.指針的計算操作(例如:++)是沒有 被定義的
2.auto_ptr不允許使用原始指針進行賦值操作,只能使用原始指針進行構造函數的初始化。
也就是說:
std::auto_ptr<ClassA> ptr1(new ClassA); //OK
std::auto_ptr<ClassA> ptr2 = new ClassA; //ERROR
auto_ptr的神祕面紗:擁有權的轉移
擁有權(Ownership)是auto_ptr最重要的概念之一。對於一個auto_ptr來說,它會主動釋放它所擁有的資源。所以,對於資源的擁有權應該是唯一的。在同一時間,一個資源應該只能被一個auto_ptr所擁有(否則可能會造成double delete的crash)。
那麼,涉及到一個很重要的注意點:auto_ptr的拷貝構造函數和賦值操作符,是如何動作的呢。
看這樣的代碼,在進行copy construct之後,ClassA的資源,實際上已經被轉移到ptr2中了,那麼ptr1呢?!這點非常關鍵(同時所引起的問題也是致命的),ptr1內部,實際上已經是空指針了!!ptr1不在擁有(釋放了)對資源的擁有權(保證擁有權的唯一性)。
同理,賦值操作符也是進行同樣的操作。這便是auto_ptr最神祕的面紗~~
- auto_ptr的在函數調用中的情況
1. 傳值方式的函數調用:會將擁有權傳入函數內部,同時函數執行結束後,會釋放資源。
2. 返回值方式的函數調用:會將函數申請的資源返回caller,caller退出後,將會釋放資源。
- 注意點
1.不要隨便使用傳值方式的auto_ptr函數調用,因爲這樣會釋放你的資源
2.企圖使用引用方式的函數調用,可能會在函數內部被賦值操作轉移擁有權,這是很不好的調用方式。
3.使用const的引用方式,可以減少無意識的擁有權轉移的問題。
4.對於const方式的引用,其實可能更像是一個T* const p,而不是const T* p
- 有關auto_ptr的使用事項
1.一定不要使用auto_ptr共享一個資源的擁有權
2.不能使用auto_ptr存儲數組指針,因爲只有auto_ptr執行的是delete對,而不是delete []
3.auto_ptr不是被設計爲引用計數的智能指針,所以,不要試圖按照這種想法去使用
4.auto_ptr是不能被STL中的標準容器使用的,因爲其中的賦值操作,會轉移ownership,這會造成意想不到的問題。
- auto_ptr的內幕
值得注意的是,reset函數執行的操作,是先delete內部資源,再重新獲得新的資源。
get()不改變擁有權,release()會放棄擁有權(賦值NULL)