gcc shared_ptr 复制赋值实现
gcc shared_ptr copy assignment implementation
我正在扫描 GCC 5 中的 shared_ptr
实现,我看到了以下内容:
__shared_ptr&
operator=(__shared_ptr&& __r) noexcept
{
__shared_ptr(std::move(__r)).swap(*this);
return *this;
}
我的问题是为什么在 交换之前临时 的附加移动构造?我假设编译会消除任何额外的开销——但为什么不直接调用 __r.swap(*this)
?我是否缺少一些聪明的副作用?
我看到 class 中的其他函数也使用相同的模式实现,我可以理解接受 const 引用但接受右值引用的情况?
因为我们需要在引用的右值上调用析构函数以减少实例计数。
首先,这就是标准所说的,GCC 完全遵循它。
这样赋值运算符有一个后置条件__r.empty()
,你的建议无法实现,所以按照你的建议实施它会对标准所说的产生不同的影响,因此是非符合。
即这个断言成立:
auto p1 = std::make_shared<int>(1);
auto p2 = std::make_shared<int>(2);
p1 = std::move(p2);
assert( !p2 );
"clever side effect"是你创建了一个新的emptyshared_ptr,它在交换后最终保留了*this
的旧值,然后超出范围。这意味着 *this
的旧值不会在 __r
.
中结束
通过将 __r
的内脏移动到作为函数 return
s 销毁的临时对象中,确保移出的对象 __r
指向处于空状态。我猜他们想把这个逻辑放在一个地方,移动构造函数,看起来像这样。
__shared_ptr(__shared_ptr&& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount()
{
_M_refcount._M_swap(__r._M_refcount);
__r._M_ptr = 0;
}
就我个人而言,我更喜欢以下实现,据我所知,它是等效的。
widget&
operator=(widget&& other) noexcept
{
widget temp {};
swap(*this, temp);
swap(*this, other);
return *this;
}
它可以用这样实现的移动构造函数来补充。
widget(widget&& other) noexcept : widget {}
{
swap(*this, other);
}
我假设有一个
void
swap(widget&, widget&) noexcept;
ADL 可以找到的重载以及 widget
的默认构造函数是 noexcept
。
我正在扫描 GCC 5 中的 shared_ptr
实现,我看到了以下内容:
__shared_ptr&
operator=(__shared_ptr&& __r) noexcept
{
__shared_ptr(std::move(__r)).swap(*this);
return *this;
}
我的问题是为什么在 交换之前临时 的附加移动构造?我假设编译会消除任何额外的开销——但为什么不直接调用 __r.swap(*this)
?我是否缺少一些聪明的副作用?
我看到 class 中的其他函数也使用相同的模式实现,我可以理解接受 const 引用但接受右值引用的情况?
因为我们需要在引用的右值上调用析构函数以减少实例计数。
首先,这就是标准所说的,GCC 完全遵循它。
这样赋值运算符有一个后置条件__r.empty()
,你的建议无法实现,所以按照你的建议实施它会对标准所说的产生不同的影响,因此是非符合。
即这个断言成立:
auto p1 = std::make_shared<int>(1);
auto p2 = std::make_shared<int>(2);
p1 = std::move(p2);
assert( !p2 );
"clever side effect"是你创建了一个新的emptyshared_ptr,它在交换后最终保留了*this
的旧值,然后超出范围。这意味着 *this
的旧值不会在 __r
.
通过将 __r
的内脏移动到作为函数 return
s 销毁的临时对象中,确保移出的对象 __r
指向处于空状态。我猜他们想把这个逻辑放在一个地方,移动构造函数,看起来像这样。
__shared_ptr(__shared_ptr&& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount()
{
_M_refcount._M_swap(__r._M_refcount);
__r._M_ptr = 0;
}
就我个人而言,我更喜欢以下实现,据我所知,它是等效的。
widget&
operator=(widget&& other) noexcept
{
widget temp {};
swap(*this, temp);
swap(*this, other);
return *this;
}
它可以用这样实现的移动构造函数来补充。
widget(widget&& other) noexcept : widget {}
{
swap(*this, other);
}
我假设有一个
void
swap(widget&, widget&) noexcept;
ADL 可以找到的重载以及 widget
的默认构造函数是 noexcept
。