C++11智能指針之weak_ptr



    weak_ptr是一種弱智能指針,它具有類似shared_ptr的行爲,但是卻不會影響的它所指向的資源的引用計數。Weak_ptr不能被解引用,也不能被測試是否爲null

weak_ptr之所以具備這些特點,是因爲weak_ptr不是一個獨立的指針,而是shared_ptr的一個附加物。Weak_ptr 是通過shared_ptr創建出來的,正像如下代碼:

    auto spw =std::make_shared<Investment>();

std::weak_ptr<Investment>wpw(spw);

如果此時,將spw賦值爲nullspw所管理的資源會被析構,那麼wpw也就成爲了懸空指針,也稱爲“過期”(expired),可以通過expired()判斷weak_ptr是否過期。

    spw = nullptr;

if (!wpw.expired()) {}

 

在使用weak_ptr時,我們通常會考慮先用expired()判斷其是否過期,如果沒有過期,就通過它來訪問所管理的資源,但是我們在一開頭的時候說過,weak_ptr不能被解引用,所以,自然我們也不可能用它來訪問它所指向的資源,即便weak_ptr可以被解引用,這麼做也是不安全的,因爲判斷是否過期和解引用是兩個獨立的動作,在多線程環境下,會出現線程競爭,所以這不是一種線程安全的做法。

正確的做法是,當我們想要訪問weak_ptr所指向的資源時,應當將weak_ptr轉爲一個shared_ptr,通過shared_ptr來訪問資源。這裏有兩種方法來做這件事:

1通過weak_ptrlock()調用

std::shared_ptr<Investment>spw1 = wpw.lock();// 如果wpw過期,則返回null

2weak_ptr作爲shared_ptr構造函數的參數

std::shared_ptr<Investment>spw2(wpw);

        那麼,既然weak_ptr無法被解引用,那它到底有什麼用處呢?

        weak_ptr的用處主要體現在兩方面:

  1. 需要獲知所管理的資源是否過期

設想在觀察者模式中,最重要的兩個角色是主體和觀察者,主體中擁有某種資源,並且維護了一個觀察者列表,當主體擁有的某種資源的狀態發生變化時,主體就會通知觀察者列表中的觀察者,觀察者得到這個通知後,會針對這個變化進行相應的操作。

在觀察者模式中,主體無法主宰觀察者列表中的觀察者的生命週期,它只需要知道,在列表中的這些觀察者是否“健在”就可以了,所以,我們可以用一個元素類型爲weak_ptr的列表來存放主體所擁有的觀察者了。

        2. 解決shared_ptr的循環引用問題

shared_ptr的循環引用是指兩個對象中都有一個shared_ptr指向另一個對象的情況,如圖所示:

 

       如果A要析構的話,就會首先嚐試去銷燬它所管理的資源,即銷燬B, 但是B中也有一個shared_ptr指向了AB要析構,也會去嘗試首先銷燬它所擁有的資源,即銷燬A,這樣的話,就會出現無限循環,兩個對象都無法被銷燬,從而造成內存泄漏。

        解決循環引用的辦法就是,使用weak_ptr,如圖所示,在B中使用weak_ptr指向A,這時候就不會出現循環引用的問題了

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