应将复制赋值运算符利用std::swap作为一般规则



始终使用std::swap实现我的复制赋值运算符是一种好的常规做法吗?我的理解是,这提供了一种共享复制构造函数实现的方法。我希望避免复制实际的复制逻辑本身。所以我要做的是:

class Foo
{
public:
    Foo(Foo const& other) { /* assume valid implementation */ }
    Foo& operator= (Foo other)
    {
        std::swap(*this, other);
        return *this;
    }
};

将"other"传递到赋值运算符中的行为执行复制构造(在这一点上,我们已经共享了复制逻辑)。我假设交换将调用move构造(这里有一个编译器生成的实现)。

自从作业&构造函数从来没有不同的实现。

您的代码没有move构造函数。你的复制构造函数阻止了移动构造函数的自动创建,而试图移动你的类却复制了它

对于移动分配,您的operator=也会阻止其自动实现,并且可以在其位置使用。

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

如果遵循0规则,则不需要复制构造函数、移动构造函数、移动赋值、复制赋值或析构函数。如果你写了其中的任何一个,你应该准备好写所有的。

使用std::swap可能很有用,但因为您必须编写移动分配和移动构造,所以根据std::swap执行任何一项都是等待发生的无限递归。

如果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%的速度命中(对于此测试)。

最新更新