代码之家  ›  专栏  ›  技术社区  ›  Srikanth

引用计数智能指针的引用计数是如何工作的?

  •  32
  • Srikanth  · 技术社区  · 17 年前

    是否维护了一个所有人都可以访问的类似地图的对象 shared_ptr shared_ptr ,这是我想到的第一个想法。

    在这些引用计数智能指针的情况下,是否有可能发生内存泄漏?如果是这样,我该如何避免它们?

    7 回复  |  直到 17 年前
        1
  •  68
  •   Ferruccio    17 年前

    1. 参考计数器。每份副本 智能指针然后接收 指向实际对象的指针和 指向引用计数的指针。
    2. 对象。引用计数为 名单。销毁后,每 智能指针从中删除

    如果你去 here

        2
  •  3
  •   sharptooth    17 年前

    每个智能指针对象都包含一个共享引用计数——每个原始指针对应一个。

    你可以看看 this 文章。此实现将这些存储在一个单独的对象中,该对象会被复制。你也可以看看 boost's documentation 或者看看 Wikipedia article

        3
  •  3
  •   Gabriel Southern    11 年前

        4
  •  2
  •   bayda    17 年前

    使用引用计数指针泄漏内存的最简单方法是创建循环。例如,一个所有指针都是shared_ptr且至少有两个元素的双链表保证不会被删除。即使外部指针被释放,内部指针仍将计数,引用计数也不会达到0。至少在最朴素的实现中是这样。

    循环问题最简单的解决方案是将shared_ptr(引用计数指针)与不共享对象所有权的弱指针混合使用。

    共享指针将共享资源(指针)和附加的reference_count信息。当你使用弱指针时,引用计数会加倍:有一个共享指针引用计数和一个弱指针引用计数。每当共享指针计数达到0时,资源就会被释放,但reference_count信息会一直保持活动状态,直到最后一个弱指针被释放。

        5
  •  2
  •   Cătălin Pitiș    17 年前

    当你复制shared_ptr对象时,它会复制带有引用计数的指针,增加引用计数,并将指针复制到包含的对象上。

        6
  •  2
  •   David Rodríguez - dribeas    17 年前

    原则上,你有一个“轻”指针类,它包含一个指向持有引用的类的指针,该类知道递增/递减引用并销毁指针对象。该引用计数类指向要引用的对象。

        7
  •  0
  •   Abhishek A Udupa    6 年前

    让我们来看一些代码:

    template <class T>
    class SharedPtr
    {
        T* m_ptr;   
        unsigned int* r_count;  
    public:
        //Default Constructor
        SharedPtr(T* ptr) :m_ptr{ ptr }, r_count{ ptr ? new unsigned int : nullptr }
        {
            if (r_count)
            {
                *r_count = 1;
            }
        }
    
        //Copy Constructor
        SharedPtr(SharedPtr& ptr) :m_ptr{ ptr.m_ptr }, r_count{ ptr.m_ptr ? new unsigned int : nullptr }
        {
            if (ptr.r_count)
            {
                ++(*ptr.r_count);
                r_count = ptr.r_count;
                m_ptr = ptr.m_ptr;
            }
        }
    
        //Copy Assignment
        SharedPtr& operator=(SharedPtr& ptr)
        {
            if (&ptr == this)
                return *this;
            if (ptr.r_count)
            {
                delete m_ptr;
                ++(*ptr.r_count);
                r_count = ptr.r_count;
                m_ptr = ptr.m_ptr;
            }
            return *this;
        }
    
        //Destructor
        ~SharedPtr()
        {
            if (r_count)
            {
                --(*r_count);
                if (!(*r_count))
                {
                    delete m_ptr;
                    delete r_count;
                }
            }
        }
    };
    

    SharedPtr

    内部变量

    内部指针 m_ptr

    一个指针 共享Ptr 共享Ptr 对象,这就是为什么我们需要一个参考计数系统来跟踪有多少个 共享Ptr 对象在程序生命周期的任何时间点管理此指针指向的内存。

    参考计数器 r_count

    共享Ptr 管理同一内存的对象。这是共享的,因为每个 共享Ptr 管理内存的对象应该知道其他对象的计数 共享Ptr 共享Ptr

    共享Ptr 对象被物化以管理已由其他对象管理的内存 共享Ptr 共享Ptr 对象死亡,因此其他对象 共享Ptr 对象知道,他们的一个管理家庭维护的记忆的家庭成员已经去世,不再管理记忆。

    缺省构造

    当一个新 共享Ptr m_ptr 被初始化为需要管理的堆分配内存地址。由于这是对该指针的第一个也是唯一一个引用,因此引用计数器

    这就是真正的引用计数发生的地方。

    每当有新的 共享Ptr 共享Ptr 共享Ptr 引用另一个 共享Ptr 即基本上当一个新的 共享Ptr 对象(现有的或新创建的)用于管理已由其他人管理的内存 共享Ptr object/s,内部指针变量 m_ptr 使这个新管理器的引用计数指向要管理的存储器地址,并且该族的引用计数增加1。

    析构函数

    共享Ptr ,它确保在释放内存之前,没有其他对正在管理的内存的引用。所有这些都发生在对象Destructor中。

    正如你在代码中看到的,只有当对内存的引用计数为0时,对象才会在它死亡之前释放内存。

    这很重要,因为,你看,如果 共享Ptr 当r_count不为0时,对象会释放内存,其他 共享Ptr 管理同一内存的对象会在之后的某个时候尝试访问它,结果会导致程序崩溃。

    共享Ptr 通过将释放内存的责任交给管理内存的最后一个幸存对象,确保不会发生这种情况。由于设计 共享Ptr