总是使用std::swap
来实现我的副本赋值运算符是一种很好的通用做法吗?我的理解是,这提供了一种共享复制构造函数实现的方法。我想避免重复实际的复制逻辑本身。所以这就是我要做的事情:
class Foo
{
public:
Foo(Foo const& other) { /* assume valid implementation */ }
Foo& operator= (Foo other)
{
std::swap(*this, other);
return *this;
}
};
将“other”传递给赋值运算符的行为执行复制构造(此时我们共享了复制逻辑)。我假设交换将调用移动构造(这里有一个编译器生成的实现)。
我一直在为我实现复制构造的每个类都这样做,因为分配&构造函数永远不会有不同的实现。
答案 0 :(得分:10)
您的代码没有移动构造函数。您的复制构造函数阻止自动创建移动构造函数,并尝试移动您的类而不是复制它。
对于move-assign,您的operator=
也会阻止其自动实现,并且可以在其位置使用。
最终结果是an infinite recursive call of =
(live code)。
如果遵循规则0,则既不需要复制构造函数,也不需要移动构造函数,移动赋值,复制赋值或析构函数。如果你写任何一个,你应该准备写所有这些。
使用std::swap
可能很有用,但是因为你必须编写move-assign和move-construct,所以根据std::swap
进行无限递归是等待发生的。
答案 1 :(得分:9)
如果Foo
包含非静态数据成员std::vector
或std::string
,或者包含包含vector
或string
的数据成员(即使是间接的),那么这可能是一种非常有效的减慢代码速度的方法。它甚至可以比调用std::sleep_for
更有效,因为后者不会在移动设备上浪费电池电量。
原因是调用vector
或string
副本分配的副本分配有机会重用容器的容量。而swap
成语始终会抛弃容量。
有关详细信息,请参阅我的ACCU 2014 talk, slides 43-53。
请特别注意此性能图表,其中显示调用vector
的复制赋值运算符与使用vector
数据成员执行复制/交换习惯用语的速度增加。
this http://howardhinnant.github.io/accu_2014_48.pdf
充其量,复制/交换习惯用法与使用vector
的复制分配一样快(当容量永远不够时)。在最坏的情况下(当容量总是足够时),复制/交换速度将快8倍。平均而言,复制/交换需要达到70%的速度(对于此测试)。