gcc共享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)
呢?我遗漏了一些聪明的副作用吗?
我看到类中的其他函数也使用相同的模式来实现,我可以理解接受常量引用,但接受右值引用的情况?
首先,标准就是这么说的,GCC只是不折不扣地遵循它。
这样,赋值操作符有一个__r.empty()
的后置条件,这是你的建议无法实现的,所以按照你的建议执行它会产生与标准所说的不同的效果,因此是不符合的。
即该断言成立:
auto p1 = std::make_shared<int>(1);
auto p2 = std::make_shared<int>(2);
p1 = std::move(p2);
assert( !p2 );
"聪明的副作用"是,您创建了一个新的空shared_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;
}
它可以用这样实现的move构造函数来补充。
widget(widget&& other) noexcept : widget {}
{
swap(*this, other);
}
我假设有
void
swap(widget&, widget&) noexcept;
ADL可以找到的重载并且CCD_ 10的默认构造函数是CCD_。
相关文章:
- 给定一个指向堆分配内存的指针,智能指针实现如何为其找到合适的释放函数?
- 未分配被释放的指针(将堆栈实现为链表时)
- 如何有效地实现将向量的数据分配给多个变量?
- 在内存中连续分配的多维数组的实现
- 如何实现,错误分配中止而不是抛出异常
- 有没有办法自动实现 sprintf 的缓冲区分配?
- 我如何实现向量重新分配
- 将模板化实现分配给先前声明的函数
- 在使用表达模板的矩阵库中实现一个行类别的分配运算符
- 实现unique_ptr:删除未分配的对象
- 如何在链接列表类中实现分配运算符
- 为什么完美的转发(全部捕获)不能实现复制分配?
- 了解循环缓冲区实现的内存分配性质
- 如何实现分配器感知的容器分配
- 实现对象列表时,如何处理动态分配
- 复制/移动操作符是否可以安全地用于实现复制/移动分配操作符
- 每次复制实现移动分配的非 const 对象时,我是否总是获得移动语义
- 在C/C 中实现实时最佳拟合内存分配算法
- C/C++ 中的非 GPL 开源潜在狄利克雷分配实现/库
- gcc共享ptr副本分配实现