爲什麼需要weak_ptr?
因爲雖然我們可以使用shared_ptr指針,但是不得不說使用shared_ptr還有一些不美好的地方需要注意和解決,所以我們的weak_ptr也是爲了幫助解決這些問題而設計出來的。
問題如下:
- 環向指向:兩個共享指針之間互相指向,所以就永遠也不會出現計數器減爲0的情況出現所以,就不會釋放資源。
- 想共享但是不願意擁有:比如說引用的壽命其實比引用的對象存活時間長,所以shared_ptr也不可能釋放對象,一般的指針判斷不出來它們指向的對象已經失效
weak_ptr指針的特點
允許共享但是不擁有對象, 這個class會建立起一個shared pointer,一旦最末的一個該對象的shared pointer失去了所有權,所有的weak ptr都會自動成空,因而,在default和copy函數以外class weak_ptr只提供“接受一個shared_ptr”的構造函數。
不能使用*或者->來訪問weak_ptr裏面的所指向的對象,而是必須建立起另外一個shared pointer,這樣設計的原因:
- 在weak_ptr之外建立一個shared_ptr這樣可以檢驗weak_ptr裏面存的指針還有沒有效,如果沒有就會拋出異常或者建立一個empty shared pointer
- 當指向的對象正在被處理的時候,shared pointer無法被釋放
- weak只是提供小批量操作,只夠創建、複製、賦值weak ptr以及轉換爲shared pointer
使用的一個例子
class Person{
public:
string name;
shared_ptr<Person> mom;
shared_ptr<Person> dad;
vector<shared_ptr<Person> > kids;
Person(string myName,
shared_ptr<Person> &mother,
shared_ptr<Person> &father):
name(myName),mom(mother),dad(father){}
};
仔細觀察上面的這個Person類,裏面不僅有兩個父親母親的shared_ptr同時每個父母都要記錄自己的孩子,放在vector裏面保存一份,最後就是一個循環,一個Person希望釋放自己的shared_ptr但是,在它的父母類裏面保存了一份在vector裏面,如果要釋放父母的話,也不允許,因爲保存了一份在子類裏面。所以修改方式就是將vector元素類型改成weak_ptr就可以解決這個問題。
想要確定weak_ptr背後的對象是否存活?
- 調用expired(),它會在weak_ptr不在共享對象時返回true,這等同於檢查use_count()是否爲0,但速度較快
- 可以使用相應的shared_ptr構造函數明確將weak_ptr轉換爲一個shared_ptr,如果被指對象已經不存在,該構造函數會拋出一個bad_weak_ptr異常。
- 調用use_count()則會詢問使用的對象的數量,如果返回0表示不存在任何有效的對象,通常只應爲調試而使用,use_count效率不總是很高