2016-08-15 46 views
0

当您使用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。如果我们首先增加lhs之前递减this,那么我们可以确定lhs不会在我们递减this时被销毁。

但这是否标准实际上在这里指定的顺序?据我所看到的,标准说的唯一的事情是,拷贝赋值运算符是等效于表达式:

shared_ptr(lhs).swap(*this) 

但我真的不能换我的头周围的影响(如果有的话),这等效可能与递减/增加参考计数的顺序有关。

因此,没有这里的标准指定的订单?或者是这个实现定义的行为?

回答

1

它必须首先递增基准计数器,万一rhsthis。否则,当参考计数器为1时,它可能会无意中销毁指针。它可以检查是否this == &rhs,但如果在减量之前执行参考计数器递增,则不需要此检查。

shared_ptr(lhs).swap(*this)因为它首先创建一个副本,从而第一递增引用计数器不从这个问题受到影响。

3

标准说[20.7.2.2。3]

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

具有等同于

shared_ptr(r).swap(*this) 

这意味着构建临时,其中递增的r引用计数,然后用*this交换其数据,然后破坏该临时,这意味着递减效果过去属于*this的引用计数。