【问题标题】:Why do C++ smart pointer implementations keep the reference counter on the heap together with the pointee?为什么 C++ 智能指针实现将引用计数器与指针保持在堆上?
【发布时间】:2012-03-06 04:41:21
【问题描述】:

阅读 Alexandrescu 和 wikipipidia 我看到指针和引用计数器存储在堆上。然后提到引用计数效率低下,因为计数器必须在堆上分配?为什么不入栈?

【问题讨论】:

  • 你能举个例子来说明你所描述的吗?
  • “引用计数器”和“堆”都只是实现细节。真正的问题是共享所有权语义只能通过动态分配来实现。

标签: c++ design-patterns boost smart-pointers loki


【解决方案1】:

因为一旦智能指针的当前实例超出范围,您就会丢失它。

智能指针用于模拟动态分配的自动存储对象。智能指针本身是自动管理的。因此,当一个被销毁时,它存储在自动存储中的任何内容也将被销毁。但是您不想丢失参考计数器。所以你将它存储在动态存储中。

【讨论】:

    【解决方案2】:

    它不能存储在堆栈上,因为这样对象的副本也会导致引用计数的副本,这会破坏其目的。

    【讨论】:

      【解决方案3】:

      正如其他人指出的那样,堆栈不是保存引用计数的合适位置,因为对象可能比当前堆栈帧的寿命更长(在这种情况下,引用计数会消失!)

      值得注意的是,与将引用计数放在堆上相关的一些低效率可以通过将其与对象本身“一起”存储来克服。在 boost 中,这可以通过使用 boost::make_shared(对于 shared_ptr's)或 boost::intrusive_ptr 来完成。

      【讨论】:

        【解决方案4】:

        有不同类型的智能指针,设计用于不同的目的。您所说的指针是共享智能指针 (std::shared_ptr),它有助于从多个位置共享对象所有权。 shared_ptr 的所有副本都会递增和递减相同的计数器变量,该变量位于堆上,因为即使在第一个副本死亡后,它也需要可供 shared_ptr 的所有副本使用。

        所以,shared_ptr 在内部保留了两个指针:指向对象和指向计数器。伪代码:

        class SharedPointer<T> {
        public:
        // ...
        private:
            T* obj;
            int* counter;
        }
        

        顺便说一句,当您使用std::make_shared 创建对象时,实现可能会通过分配足够的内存来容纳计数器和对象然后并排构造它们来优化分配。

        这个极端的技巧给了我们一个侵入式引用计数模式:对象内部保存它的计数器并提供AddRefRelease 函数来增加和减少它。您可以使用侵入式智能指针,例如boost::intrusive_ptr,它使用这种机制,因此不需要分配另一个单独的计数器。这在分配方面更快,但需要将计数器注入受控类定义。

        另外,当您不需要共享对象所有权而只需要控制它的生命周期(这样在函数返回时会被破坏)时,您可以使用作用域智能指针std::unique_ptrboost::scoped_ptr。它完全不需要计数器,因为只有一个 unique_ptr 的副本存在。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-03-20
          • 1970-01-01
          • 2015-10-30
          • 1970-01-01
          • 1970-01-01
          • 2016-09-14
          • 2011-06-14
          • 2011-07-25
          相关资源
          最近更新 更多