复制赋值运算符是否应该将std :: swap作为一般规则?

voi*_*ter 6 c++ c++11

使用总是实现我的复制赋值运算符是一种很好的通用做法std::swap吗?我的理解是,这提供了一种共享复制构造函数实现的方法.我想避免重复实际的复制逻辑本身.所以这就是我要做的:

class Foo
{
public:
    Foo(Foo const& other) { /* assume valid implementation */ }

    Foo& operator= (Foo other)
    {
        std::swap(*this, other);
        return *this;
    }
};
Run Code Online (Sandbox Code Playgroud)

将"other"传递给赋值运算符的行为执行复制构造(此时我们共享了复制逻辑).我假设交换将调用移动构造(这里有一个编译器生成的实现).

我一直在为每个实现复制构造的类做这个,因为赋值和构造函数从来没有不同的实现.

Yak*_*ont 10

您的代码没有移动构造函数.您的复制构造函数阻止自动创建移动构造函数,并尝试移动您的类而不是复制它.

对于move-assign,您operator=还会阻止其自动实现,并且可以在其位置使用.

最终结果是(实时代码)的无限递归调用=.

如果遵循规则0,则既不需要复制构造函数,也不需要移动构造函数,移动赋值,复制赋值或析构函数.如果你写任何一个,你应该准备写所有这些.

使用std::swap可能是有用的,但因为你必须写你的举动,分配和布展施工,在方面表现要么std::swap是无限循环等待发生.

  • 你是对的:你不能用'std :: swap`来实现`operator =`; 你可以用你自己的*("优化")`swap`来实现它.运算符通常的复制和交换习惯使用自定义`swap`(成员函数). (3认同)

How*_*ant 9

如果Foo包含非静态数据成员std::vectorstd::string,或包含包含数据成员vectorstring(如即使是间接的),那么这可能是一个非常放慢你的代码的有效途径.它甚至可以比呼叫更有效,std::sleep_for因为后者不会在移动设备上浪费电池电量.

原因是调用vectorstring复制赋值的复制赋值有机会重用容器的容量.而swap成语总是抛弃容量.

有关详细信息,请参阅我的ACCU 2014演讲,幻灯片43-53.

特别要注意的是这个性能图表,它显示了调用vector复制赋值运算符与使用vector数据成员执行复制/交换习惯用语的速度增加.

这http://howardhinnant.github.io/accu_2014_48.pdf

充其量,复制/交换习惯用语与使用vector复制分配一样快(当容量永远不够时).在最坏的情况下(当容量总是足够时),复制/交换速度将快8倍.平均而言,复制/交换需要70%的速度命中(对于此测试).