shared_ptr <>不需要使用引用计数?

tow*_*owi 3 reference-counting shared-ptr c++11

难道我的理解是,新标准的权利shared_ptr并不需要使用引用计数?只有它可能以这种方式实现?

我可以想象一个以某种方式使用隐藏链表的实现.在N3291"20.7.2.2.5.(8)shared_ptr观察者[util.smartptr.shared.obs]"

[注意:use_count()不一定有效. - 结束说明]

这给了我这个想法.

一二三*_*一二三 5

你是对的,规范中没有任何内容要求使用明确的"计数器",并且存在其他可能性.

例如,建议使用链接列表实现boost的实现shared_ptr ; 但是,该提案最终被拒绝,因为它引入了其他领域的成本(规模,复制操作和线程安全).


cur*_*guy 5

摘要说明

有人说这shared_ptr是一个"参考计数器智能指针".我不认为这是看待它的正确方法.

实际上shared_ptr是所有关于(非独占)所有权的:所有 shared_ptr那些是shared_ptr用指针初始化的副本p都是所有者.

shared_ptr跟踪所有者的集合,保证:

  • 虽然所有者的集合是非空的,但delete p不会被调用
  • 当所有者集合变空时,立即调用delete p(或D销毁函子的副本);

当然,要确定所有者集合何时变空,shared_ptr只需要一个计数器.抽象描述稍微容易思考.

可能的实现技术

为了跟踪所有者的数量,计数器不仅是最明显的方法,使用原子比较和修改如何使线程安全也是相对明显的.

为了跟踪所有所有者,所有者的链接列表不仅是明显的解决方案,而且还是一种避免为每组所有者分配任何内存的简单方法.问题是要使这种方法有效地保证线程安全并不容易(任何事情都可以通过全局锁定使线程安全,这违背了并行性的想法).

在多线程实现的情况下

一方面,我们有一个小的,fix-size(除非使用自定义销毁函数)内存分配,这很容易优化,并且简单的整数原子操作.

另一方面,存在昂贵且复杂的链表处理; 如果需要每个所有者设置互斥量(我认为是这样),内存分配的成本又回来了,此时我们可以用计数器替换互斥锁!

关于多种可能的实现

我读过多少次"标准"类可以实现多种实现?

谁从未听过这种可以作为极坐标实现的复杂类的幻想?众所周知,这是愚蠢的.复数必须使用笛卡尔坐标.如果首选极坐标,则必须创建另一个类.极地复杂类不可能被用作通常的复杂类的替代品.

对于(非标准)字符串类也是如此:没有理由让字符串类在内部终止NUL并且不将长度存储为整数,只是为了重复调用的有趣和低效率strlen.

我们现在知道,设计std::string容忍COW是一个坏主意,这是const迭代器不寻常的失效语义的原因.

std::vector 现在保证是连续的.

幻想的结束

在某些时候,必须放弃标准类具有许多显着不同的合理实现的幻想.标准类是原始构建块; 它们不仅应该非常有效,而且应该具有可预测的效率.

程序员应该能够对基本操作的相对速度做出可移植的假设.如果即使最简单的加法变成一组超越计算,复杂类对于严重的数字运算也是无用的.如果不保证字符串类通过数据共享具有非常快的副本,则程序员必须最小化字符串副本.

实施者可以自由选择不同的实现技术,只有当它不能使普通的廉价操作成本极高时(相比之下).

对于许多类来说,这意味着只有一个可行的实现策略,有时会有一些自由度(比如a中块的大小std::deque).