为什么C ++智能指针实现将引用计数器与指针一起保留在堆上?

时间:2012-02-14 19:46:39

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

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

4 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:3)

它不能存储在堆栈中,因为那时对象的副本也会产生refcount的副本,这会破坏其目的。

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

有不同类型的智能指针,专为不同目的而设计。您正在谈论的指针是共享智能指针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,它使用这种机器,因此不需要分配另一个单独的计数器。这在分配方面更快,但需要将计数器注入受控类定义。

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