指標在c++中非常重要,但使用它也帶來了許多問題,即讓指標與其所指物件擁有相同的生命週期,特別是當有多個指標指向同乙個物件時,這是十分困難的.當有多個指標指向同乙個物件時,當其中乙個指標銷毀時,不讓能其它指標出現空懸指標的現象,也不能讓該物件被銷毀多次;當最後乙個指標被銷毀時,必須同時銷毀該物件,不能造成資源洩漏.
避免上述問題的通常做法是使用智慧型指標(smart pointer),當它是指象物件的最後乙個指標時,在它銷毀時,也會將它指向的物件銷毀.c++11起標準庫提供了兩個型別的智慧型指標:
shared_ptr 共享式擁有的智慧型指標.該類指標允許多個指標指向同乙個物件,該物件會在最後乙個指標被銷毀時同時被銷毀釋放.
unique_ptr 獨佔式擁有的智慧型指標.該類指標保證在同一時間內只有乙個智慧型指標指向了物件,可以移交擁有權,對於避免資源洩漏特別有用.
多個shared_ptr可以共享同乙個物件,當物件的最後乙個擁有者銷毀時,它有責任銷毀物件並清理與該物件相關的所有資源.shared_ptr的目標就是在其所指向的物件不再被需要之後自動釋放與物件相關的資源.
shared_ptr可以像使用其它指標一樣使用它,可以進行賦值,拷貝,比較等操作.shared_ptr定義在memory標頭檔案中.
#include #include #include #include using namespace std;
int main()
cout << endl;
*pnico = "nicolai";
for (auto ptr:whomadecoffee)
cout << endl;
cout << "use_count:" << whomadecoffee[0].use_count() << endl;
//use_count()方法會統計當前物件有多少個shared_ptr指標
system("pause");
return 0;
}複製**
在定義並初始化shared_ptr指標時,建議使用make_shared的方式,因為這種方式比較安全,它使用的是一次分配.而另外一種方式是先定義乙個shared_ptr指標,然後再給它賦值乙個新的指標,但此時必須用reset()方法.
shared_ptrpnico;
pnico = new string("nico"); //這是不允許的
pnico.reset(new string("nico"));
複製**
在宣告初始化shared_ptr指標時,也可以為其自定義乙個delete函式,如下:
shared_ptrpnico(new string("nico"), (string *p) );
複製**
在預設情況下,shared_ptr呼叫的預設delete函式為delete,而不是delete,這意味著當shared_ptr在釋放物件時,只對單一物件是有效的,而對陣列是無效的,此時必須使用自定義delete函式, 或使用為unique_ptr而提供的輔助函式作為deleter。
此外,當某個物件的最後乙個shared_ptr不再指象該物件,對此物件進行析構時,當此析構過程中不僅僅是釋放記憶體時,此時必須指定自己的析構策略,即定義自定義delete函式。
weak_ptr指標允許** 共享物件卻不擁有 **該物件,當物件的最後乙個shared_ptr不再指向該物件時,任何weak_ptr指標就會自動成空。因而,weak_ptr在預設建構函式和拷貝建構函式之外,只提供了接受乙個shared_ptr的建構函式。對於weak_ptr指向的物件,不能使用*
和->操作函,必須另外建立乙個shared_ptr來指向該物件。這是合理的設計,其理由如下:
在weak_ptr指標之外建立乙個shared_ptr指標可因此檢查是否存在乙個相應物件。如果不,則操作會丟擲異常或建立乙個空的shared_ptr指標(實際究竟哪種行為乃取決於所執行的操作)。
當指向的物件正被處理時,shared_ptr指標無法被釋放。
因此weak_ptr指標只提供了小量操作,只夠用來建立、複製、賦值weak_ptr指標以及轉換為乙個shared_ptr指標,或檢查是否指向某個物件。
以下例子通過使用weak_ptr指標來避免因使用shared_ptr而引起的環向引用,使得所有shared_ptr指標無法正常釋放。
class person
; ~person() ;
private:
};shared_ptrinitfamily(const string& name)
int main()
複製**
在使用weak_ptr指標訪問被指物件時,必須在weak_ptr指標的式子上加上lock()方法,這會產生乙個新的指向該物件的shared_ptr指標。而當weak_ptr指向的物件已經釋放時,lock()操作也產生乙個空的shared_ptr指標,從而在進行*
或->操作時會引發不明確的行為。對於weak_ptr指向的物件是否還繼續存在的判斷方式有如下幾種:
呼叫expired()方法,該方法會在weak_ptr指向的物件不存在時返回true,該操作等同於檢查use_count()是否為0,但其速度更快。
使用shared_ptr建構函式顯示地將weak_ptr物件轉換為shared_ptr物件,如果weak_ptr指向的物件不存在,則建構函式會丟擲乙個bad_weak_ptr異常。
呼叫use_count()方法詢問相應物件的擁有者數量,返回0表示不存在任何有效的物件,但該方法的效率不高。
try
catch (const exception& e)
複製**
shared_ptr雖然強化了程式安全,但由於物件的相應資源往往是自動釋放的,當物件不再使用時有可能出現問題。
shared_ptr指標的迴圈依賴,這將會造成空蕩指標,即迴圈依賴中的指標指向的資源無法得到正確的釋放。
必須要確保物件只被一組shared_ptr擁有。當乙個物件被多組shared_ptr所擁有時,便有多組shared_ptr物件有權釋放相應的資源,相應的資源就會被重複釋放而產生問題。要避免這種情況,在建立物件和其相應的資源時直接建立相應的智慧型指標。
unique_ptr是一種在異常發生時可幫助避免資源洩漏的智慧型指標。一般而言,unique_ptr實現了** 獨佔式 **擁有的概念,即它可以確保乙個物件和其所擁有的資源同一時間只被乙個指標所擁有。一旦擁有者被銷毀或變成空,或開始擁有乙個新的物件,先前所擁有的物件就會被銷毀,其任何相應資源也會被釋放。
unique_ptr使用方式與尋常的指標非常相似,用*
來指向物件,用->來方問物件的成員,但它不提供指標的算術運算(如++操作等)。此外,unique_ptr不允許將乙個尋常的指標作為初始值,必須直接初始化unique_ptr指標,如下所示:
std::unique_ptrup = new int; //錯誤,不能使用尋常指標來初始化
std::unique_ptrup(new int); //正確
複製**
unique_ptr指標可以是空指標,可以不指向任何物件,可以讓其指向nullptr或呼叫reset()方法來讓其成為空指標。當呼叫unique_ptr指標的release()方法時,可以獲得unique_ptr指標所擁有的物件並放棄擁有權,如下所示:
std::unique_ptrup(new std::string("nico"));
std::string* sp = up.release();
複製**
由於unique_ptr所提供的語義是* 獨佔式擁有 *,所以不可以對unique_ptr執行尋常意義的拷貝和賦值操作,但可以使用move語義。
unique_ptr擁有權的轉移指出了它的一種用途:函式可以利用它們將擁有權轉移給其它函式,即可以將unique_ptr作為函式的入參或返回值,而不用擔心資源的洩漏。
unique_ptr可以做為類的成員而避免資源的洩漏。因為只有在一切構造動作全部完成後,析構函式才有可以被呼叫。而在建構函式執行過程中發生異常時,析構函式是不會被呼叫的,在建構函式中已分配的資源將不會被**而造成資源洩漏,用unique_ptr來代替普通的指標可以避免這種情況的發生。而且在使用unique_ptr代替普通的指標後,還可以略而不寫析構函式,使用預設析構函式即可。
陣列處理。c++標準庫為unique_ptr提供了乙個偏特化版本來處理陣列,使unique_ptr在遺失其所指向物件的擁有權時,會對該物件呼叫delete,其宣告方式如下:
std::unique_ptrup(new string[10]);
std::cout<< up[0] 《複製**
在這個版本中,unique_ptr指標不再提供*
和->操作,改為提供下標操作符來訪問陣列中的某乙個物件。
[參考]( c++11中智慧型指標的原理、使用、實現
c 智慧型指標
auto prt 它是 它所指向物件的擁有者 所以當自身物件被摧毀時候,該物件也將遭受摧毀,要求乙個物件只有乙個擁有者,注意 auto prt 不能使用new 來分配物件給他 include include using namespace std template void bad print au...
c 智慧型指標
很久沒寫部落格了,不知道如何表達了,哈哈.我先介紹一下深淺拷貝.class copy 此時a.ptr和b.ptr指向同乙個物件,當我們delete a.ptr時 b.ptr所指向的物件已經不存在了,要是我們引用b.ptr指向的物件也就會出問題了.深拷貝 把a.ptr所指向的物件拷貝乙份給b.ptr ...
c 智慧型指標
記得前不久有一次面試被問到智慧型指標的實現,當時對智慧型指標只是聽說但沒有了解過,就亂七八糟地說了一遍。今天寫了一遍智慧型指標,用了引用計數的概念。主要思想就是,用乙個新類對原本需要的型別進行了一層封裝,這個新類中儲存了原本的物件指標和乙個引用計數的指標,之所以全部用指標來儲存,就是因為會出現多個新...