Shared_ptr赋值:引用计数顺序



当您使用shared_ptr的复制赋值操作符时,从概念上讲,赋值左侧的shared_ptr需要减去它当前拥有的对象的引用计数,然后增加赋值右侧对象的引用计数。(当然,假设两个指针都是非空的。)

所以实现可能看起来像下面的伪代码:

shared_ptr& operator = (const shared_ptr& rhs)
{
   decrement_reference_count(this->m_ptr);
   this->m_ptr = rhs.m_ptr;
   increment_reference_count(this->m_ptr);
   return *this;
}

但请注意,这里我们在之前减少this 的引用计数,我们增加rhs的引用计数。我们也可以反过来做。我的问题是,标准中确实规定了顺序吗?

为什么会产生差异:如果this的引用计数与lhs的引用计数之间存在某种依赖关系,则会产生很大的差异。例如,假设两者都是链表结构的一部分,其中每个链接节点中的next指针都是shared_ptr。因此,递减结构中任何节点的引用计数都可能触发析构函数,而析构函数随后会引发链式反应,并递减引用计数(可能还会破坏)链中的每个其他节点。

因此,假设lhs的引用计数受到this的引用计数的影响,那么首先减少this还是首先增加lhs会有很大的区别。如果在对this进行递减之前先对lhs 进行递增,则可以确保在对this进行递减时lhs不会被破坏。

但是标准在这里真的指定了顺序吗?据我所知,标准唯一说的是复制赋值操作符等价于表达式:

shared_ptr(lhs).swap(*this)

但是我不能真正理解这种等价对于引用计数递减/递增的顺序可能具有的含义(如果有的话)。

那么标准在这里指定顺序了吗?或者这是实现定义的行为?

The Standard说[20.7.2.2.3]

shared_ptr& operator=(const shared_ptr& r) noexcept;

的作用相当于

shared_ptr(r).swap(*this)

这意味着构造一个临时对象,它增加r的引用计数,然后与*this交换它的数据,然后销毁临时对象,这意味着减少以前属于*this的引用计数。

如果rhsthis,则必须先增加引用计数器。否则,当引用计数器为1时,它可能会无意中销毁指针。它可以检查是否this == &rhs,但如果引用计数器的增量在减量之前执行,则此检查是不必要的。

shared_ptr(lhs).swap(*this)没有这个问题,因为它先创建一个副本,从而先增加引用计数器。

最新更新