第十六章 string類和標準模板庫(2)智能指針模板類

(二)智能指針模板類

智能指針是行爲類似指針的類對象,但這種對象還有其他便於管理內存的功能。

1.使用智能指針

(1)三個智能指針模板auto_ptr,shared_ptr,unique_ptr,都定義了類似指針的對象,可以將new獲得的地址賦值給這些對象。當智能指針過期的時候,其析構函數將使用delete來釋放指針指向的內存,也就是向正常的變量那樣使用智能指針,而不用考慮釋放它指向的內存

(2)創建智能指針對象,必須包含頭文件memory,然後使用通常的模板實例化語法來實例化所需類型的指針。比如auto_ptr<double> pd(new double);就創建了一個智能指針對象pd指向一個double類型的內存塊。new double是new返回的指針,它是構造函數auto_ptr<double>的參數。智能指針也是處於名稱空間std之內的,因此需要使用std::運算符或前面講過的其他技術。

(3)所有的智能指針都只有一個explicit構造函數,以指針作爲參數,當然也可以爲空指針。智能指針和普通指針的用法幾乎一樣,比如使用*,->等運算符。可以將普通指針作爲參數構造智能指針,也可以用new分配內存返回地址來利用構造函數構造智能指針,總之智能指針只可以顯式使用構造函數來構造,不允許隱式的賦值和構造。

智能指針可以賦值給同類型的常規指針,智能指針還可以賦值給同類型的智能指針(這樣會產生重複釋放內存的問題,會在後面解決)。

(4)有一點要注意的是,普通指針可以指向非堆上的內存,也就是普通的變量,而智能指針只能用於new運算符分配的內存,否則智能指針刪除的時候要釋放指向內存,這在普通變量中是不正確的。

2.有關智能指針的注意事項

(1)如果兩個智能指針指向同一個對象,智能指針刪除的時候,會釋放同一個對象兩次,這會造成問題,解決的方法有很多種。一種是建立所有權,這是auto_ptr和unique_ptr的策略,但unique_ptr的策略更爲嚴格,這也是auto_ptr被拋棄的原因。第二種是創建智能性更高的指針,只有最後一個指針被釋放時才delete其指向的內存,這是shared_ptr的策略。第三種是重新定義賦值運算符,進行深度複製,這樣兩個指針指向不同的對象。

(2)atuo_ptr智能指針是用所有權的形式來解決指針指向同一個內存地址的問題的,此時如果一個指針賦值給另一個指針,那麼就喪失了所有權(也就是賦值的智能指針變爲了空指針,將指向的對象的所有權交給了被賦值的指針),我如果再用這個指針訪問對象,就會出現問題,這是auto_ptr不利的地方。

(3)unique_ptr爲何優於auto_ptr?

當我們將一個unique_ptr賦值給另一個unique_ptr的時候,如果後者是一個臨時右值,編譯器允許這樣做(比如語句pu3=unique_ptr<string>(new string “yo”);是允許的,因爲該構造函數創建的臨時對象,也就是指針,在將值傳遞給pu3之後,將會被銷燬,也就是一個pu3對應於一個內存地址,這是沒有問題的);而如果源unique_ptr將要存在一段時間,那麼編譯器將不允許這樣做,這是在編譯的時候就確定的,如果錯誤會通不過編譯,而auto_ptr不能在編譯期間發現錯誤。

auto_ptr沒有上面所說的編譯期間糾錯的功能,它可以將一個auto_ptr賦值給另一個auto_ptr,這可能會在很多時候出錯,因此auto_ptr被拋棄不用。

另外,unique_ptr還有一個功能是可以使用new name[]來創建指向數組的指針,而auto_ptr只能使用new name。比如unique_ptr<double[]> aa(new double[4]);這是可以的,而如果是auto_ptr則是不被允許的,這是因爲unique_ptr析構函數定義了delete[]版本而auto_ptr沒有定義。因此,智能指針我們選擇兩種就可以了,一個unique_ptr,另一個shared_ptr,不用考慮其他了。

如果我需要將unique_ptr指針對象賦值給另一個指針對象的時候應該怎麼辦呢?(意思是我可以確保不會出現內存釋放兩次的錯誤,而且希望再用回auto_ptr的功能),此時可以使用std::move函數將一個unique_ptr對象的內容讓渡到另一個對象,比如unique_ptr<string> aa(new string(“what”));unique_ptr<string> bb;bb=aa;(不允許)bb=move(aa);(這是可以的)。

4.選擇智能指針

如果程序需要使用指向同一個對象的多個指針,此時要使用shared_ptr。而如果程序不需要多個指向同一個對象的指針,則可以使用unique_ptr,只有一個指針對對象有所有權,將其賦值給其他unique_ptr指針將不能通過編譯器。

當一個unique_ptr屬於右值時,可以將它賦值給一個shared_ptr,這與將一個unique_ptr賦值給另一個unique_ptr滿足的條件是相同的(也就是臨時的unique_ptr是可以賦值給另一個unique_ptr的,此時也可以賦值給一個shared_ptr)。將一個右值(也就是臨時指針)unique_ptr賦值給一個shared_ptr時,unique_ptr會自動轉換爲shared_ptr,並將內存控制權交給shared_ptr。

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