C++ 的強引用和弱引用


原文鏈接:C++ - 強引用和弱引用 - c++kuzhon - 博客園  https://www.cnblogs.com/kuzhon/articles/5648807.html

C++ - 強引用和弱引用_等等... 大雄,有啦!-CSDN博客  https://blog.csdn.net/gykimo/article/details/8728735

原來,我認為“為什么會有引用計數這樣的技術”是為了內存自動回收和節省內存,但是讀完下面的幾節后,內存自動回收是一個原因,但是節省內存並不是真正的原因,真正的原因是有些對象如果被復制在現實中是不合事實的。

為什么有引用計數

    C++中存在兩種語義:值語義(value sematics)和對象語義(object sematic),對象語義也可以叫做引用語義(reference sematics)。
值語義,指的是對象的拷貝與原對象無關,就像拷貝int一樣,C++的常用類型數據等都是值語義。
對象語義,指的是面向對象意義下的對象,是禁止拷貝的。

    在設計一個類的時候該類是否可以被拷貝(即具備拷貝構造函數),取決於拷貝后的語義是否成立,比如一個Thread類,拷貝后系統中並不會啟動另外一個線程,所以拷貝是禁止的。同樣類似於Employee雇員類也是。

    這么設計起碼有兩個好處:

    1. 語義合理,有些對象復制是不符合常理的

    2. 節省內存

強引用

當對象被創建時,計數為1;每創建一個變量引用該對象時,該對象的計數就增加1;當上述變量銷毀時,對象的計數減1,當計數為0時,這個對象也就被析構了。

強引用計數在很多種情況下都是可以正常工作的,但是也有不湊效的時候,當出現循環引用時,就會出現嚴重的問題,以至於出現內存泄露,如下代碼:

 

#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
 
class parent;
class children;
 
typedef boost::shared_ptr<parent> parent_ptr;
typedef boost::shared_ptr<children> children_ptr;
 
class parent
{
public:
    ~parent() { std::cout <<"destroying parent\n"; }
 
public:
    children_ptr children;
};
 
class children
{
public:
    ~children() { std::cout <<"destroying children\n"; }
 
public:
    parent_ptr parent;
};
 
void test()
{
    parent_ptr father(new parent());
    children_ptr son(new children);
 
    father->children = son;
    son->parent = father;
}
 
void main()
{
    std::cout<<"begin test...\n";
    test();
    std::cout<<"end test.\n";
}

  

運行該程序可以看到,即使退出了test函數后,由於parent和children對象互相引用,它們的引用計數都是1,不能自動釋放,並且此時這兩個對象再無法訪問到。這就引起了c++中那臭名昭著的內存泄漏。

一般來講,解除這種循環引用有下面有三種可行的方法:

1. 當只剩下最后一個引用的時候需要手動打破循環引用釋放對象。
2. 當parent的生存期超過children的生存期的時候,children改為使用一個普通指針指向parent。
3. 使用弱引用的智能指針打破這種循環引用。
雖然這三種方法都可行,但方法1和方法2都需要程序員手動控制,麻煩且容易出錯。下面就介紹弱引用

 

在多線程程序中,一個對象如果被多個線程訪問,一般使用shared_ptr,通過引用計數來保證對象不被錯誤的釋放導致其他線程訪問出現問題。
但這種引用計數解決不了循環引用的問題。
 

弱引用

boost::weak_ptr是boost提供的一個弱引用的智能指針,它的聲明可以簡化如下:
 
namespace boost {
 
    template<typename T> class weak_ptr {
    public:
        template <typename Y>
        weak_ptr(const shared_ptr<Y>& r);
 
        weak_ptr(const weak_ptr& r);
 
        ~weak_ptr();
 
        T* get() const; 
        bool expired() const; 
        shared_ptr<T> lock() const;
    }; 
}

  

 
定義變量:
shared_ptr<T>  t(new T);
weak_ptr<T> ptr(t); // t為一個T對象 
則當t被銷毀時,ptr 被自動置為無效。使用方法如下:
if ( shard_ptr<T>  safePtr  = ptr.lock() )  safePtr->Fun();
 
可以看到,boost::weak_ptr必須從一個boost::share_ptr或另一個boost::weak_ptr轉換而來,這也說明,進行該對象的內存管理的是那個強引用的boost::share_ptr。boost::weak_ptr只是提供了對管理對象的一個訪問手段。boost::weak_ptr除了對所管理對象的基本訪問功能(通過get()函數)外,還有兩個常用的功能函數:expired()用於檢測所管理的對象是否已經釋放;lock()用於獲取所管理的對象的強引用指針。
由於弱引用不更改引用計數,類似普通指針,只要把循環引用的一方使用弱引用,即可解除循環引用。對於上面的那個例子來說,只要把children的定義改為如下方式,即可解除循環引用:
 
class children
{
public:
    ~children() { std::cout <<"destroying children\n"; }
 
public:
    boost::weak_ptr<parent> parent;
};

  

最后值得一提的是,雖然通過弱引用指針可以有效的解除循環引用,但這種方式必須在程序員能預見會出現循環引用的情況下才能使用,也可以是說弱引用僅僅是一種編譯期的解決方案,如果程序在運行過程中出現了循環引用,還是會造成內存泄漏的。因此,不要認為只要使用了智能指針便能杜絕內存泄漏。畢竟,對於C++來說,由於沒有垃圾回收機制,內存泄漏對每一個程序員來說都是一個非常頭痛的問題。

 
弱引用:它僅僅是對象 存在時候的引用,當對象不存在時弱引用能夠檢測到,從而避免非法訪問,弱引用也不會修改對象的引用計數。這意味這弱引用它並不對對象的內存進行管理,在功能上類似於普通指針,然而一個比較大的區別是,弱引用能檢測到所管理的對象是否已經被釋放,從而避免訪問非法內存。
 
 
 

智能指針一個很重要的概念是“所有權”,所有權意味着當這個智能指針被銷毀的時候,它指向的內存(或其它資源)也要一並銷毀。這技術可以利用智能指針的生命周期,來自動地處理程序員自己分配的內存,避免顯示地調用delete,是自動資源管理的一種重要實現方式。

為什么要引入“弱引用”指針呢?弱引用指針就是沒有“所有權”的指針。有時候我只是想找個指向這塊內存的指針,但我不想把這塊內存的生命周期與這個指針關聯。這種情況下,弱引用指針就代表“我指向這東西,但這東西什么時候釋放不關我事兒……”

有些地方為了方便,直接用原始指針(raw pointer)來表示弱引用。然后用這種原始指針,其弱引用的含義不夠明確,萬一別人寫個delete xxxx,你就被坑了……而且弱引用指針還有其它一些方便你正確使用它的好處。

發布於 2014-11-30

作者:旺旺
鏈接:https://www.zhihu.com/question/26851369/answer/34271911
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

 
 
 

有兩個好處
1、對象被析構了,weakptr會自動等於nullptr
2、weakptr可以還原成sharedptr而不會讓引用計數錯亂

這兩者普通指針都是做不到的。
 
 
 
c++ - When is std::weak_ptr useful?
緩存。想用時候可以用,但不想因此阻止資源被釋放。
 
 
參考鏈接:
c++的弱引用指針到底是為什么目的引入的?原理是咋回事 - 知乎  https://www.zhihu.com/question/26851369
c++弱引用與強引用_aikb6223的博客-CSDN博客  https://blog.csdn.net/aikb6223/article/details/102349924
c++11 - When is std::weak_ptr useful? - Stack Overflow  https://stackoverflow.com/questions/12030650/when-is-stdweak-ptr-useful


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM