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

C++ 为什么C++;智能指针实现将引用计数器与指针对象一起保留在堆上?,c++,design-patterns,boost,smart-pointers,loki,C++,Design Patterns,Boost,Smart Pointers,Loki,阅读Alexandrescu和wikipipidia,我看到指针对象和引用计数器存储在堆上。然后提到引用计数效率低下,因为必须在堆上分配计数器?为什么它不存储在堆栈上?因为一旦智能指针的当前实例超出范围,就会丢失它 智能指针用于模拟动态分配的自动存储对象。智能指针本身是自动管理的。因此,当一个人被摧毁时,它储存在自动存储器中的任何东西也会被摧毁。但你不想失去参考计数器。因此,您将其存储在动态存储器中。它不能存储在堆栈上,因为这样一来,对象的副本也会导致refcount的副本,这将破坏其用途。正如

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

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


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

它不能存储在堆栈上,因为这样一来,对象的副本也会导致refcount的副本,这将破坏其用途。

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


值得注意的是,将引用计数放在堆上的一些低效率问题可以通过将其与对象本身“一起”存储来克服或者。

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

因此,
shared\u ptr
在内部保留两个指针:指向对象和指向计数器。伪代码:

class SharedPointer<T> {
public:
// ...
private:
    T* obj;
    int* counter;
}
类共享指针{
公众:
// ...
私人:
T*obj;
int*计数器;
}
顺便说一下,当您使用
std::make_shared
创建对象时,实现可能会通过分配足够的内存来保存计数器和对象,然后并排构建它们来优化分配

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


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

您能给出一个描述的示例吗?包括“引用计数器”和“堆”这些仅仅是实现细节,真正的问题在于共享所有权语义只能通过动态分配来实现。