阅读 Alexandrescu 和 wikipipidia 我看到指针和引用计数器存储在堆上。然后提到引用计数效率低下,因为计数器必须在堆上分配?为什么不存储在堆栈中?
4 回答
因为一旦智能指针的当前实例超出范围,您就会丢失它。
智能指针用于模拟动态分配的自动存储对象。智能指针本身是自动管理的。因此,当一个被销毁时,它存储在自动存储中的任何内容也将被销毁。但是您不想丢失参考计数器。因此,您将其存储在动态存储中。
它不能存储在堆栈中,因为对象的副本也会导致引用计数的副本,这会破坏其目的。
正如其他人指出的那样,堆栈不是保存引用计数的合适位置,因为该对象可能比当前堆栈帧寿命长(在这种情况下,引用计数会消失!)
值得注意的是,与将引用计数放在堆上相关的一些低效率可以通过将其与对象本身“一起”存储来克服。在 boost 中,这可以通过使用boost::make_shared (for shared_ptr's) 或boost::intrusive_ptr来完成。
有不同类型的智能指针,设计用于不同的目的。您所说的指针是共享智能指针( std::shared_ptr
),它有助于从多个位置共享对象所有权。递增和递减的所有副本都使用相同的计数器变量,该变量位于堆上,因为即使在第一个副本死亡后shared_ptr
,它也需要可供所有副本使用。shared_ptr
因此,shared_ptr
内部保留了两个指针:指向对象和指向计数器。伪代码:
class SharedPointer<T> {
public:
// ...
private:
T* obj;
int* counter;
}
顺便说一句,当您使用 来创建对象时std::make_shared
,实现可以通过分配足够的内存来保存计数器和对象然后并排构造它们来优化分配。
这种极端的技巧给了我们一种侵入式引用计数模式:对象在内部保存它的计数器,并提供AddRef
函数Release
来增加和减少它。您可以使用侵入式智能指针,例如boost::intrusive_ptr
,它使用这种机制,因此不需要分配另一个单独的计数器。这在分配方面更快,但需要将计数器注入受控类定义。
此外,当您不需要共享对象所有权并且只需要控制它的生命周期(这样在函数返回时会被破坏)时,您可以使用作用域智能指针:std::unique_ptr
或boost::scoped_ptr
. 它完全不需要计数器,因为只unique_ptr
存在一个副本。