由于我们已经移动了语义,所以特别推荐使用std :: swap吗?

时间:2011-12-23 14:44:16

标签: c++ templates c++11 swap move-semantics

  

可能重复:
  Move semantics == custom swap function obsolete?

这就是std::swap在C ++ 11中的样子:

template<typename T>
void swap(T& x, T& y)
{
  T z = std::move(x);
    x = std::move(y);
    y = std::move(z);
}

我是否仍然需要为我自己的类型专门化std::swap,或者std::swap会尽可能高效,前提是我的类定义了移动构造函数和移动赋值运算符吗?

4 个答案:

答案 0 :(得分:31)

std::swap的特化现在是可选的,但不会弃用。理由是表现。

对于原型设计代码,甚至可能需要大量的运输代码,std::swap也会非常快。但是,如果您需要从代码中获取每一点内容,那么编写自定义交换仍然是一个重要的性能优势。

考虑一下你的类基本上有一个拥有指针的情况,你的移动构造函数和移动赋值只需要处理那个指针。计算每个成员的机器负载和存储:

移动构造函数:1个加载和2个存储。

移动作业:2个载荷和2个商店。

自定义交换:2个加载和2个商店。

std::swap是1个移动构造和2个移动分配,或者:5个载荷和6个商店。

自定义交换可能仍然比std::swap快两到三倍。虽然任何时候你都试图通过计算货物和商店来计算某物的速度,但两者都会变得很快。

注意:在计算移动分配的成本时,请务必考虑您将进入移动值(在std::swap算法中)。这通常会以分支为代价来抵消解除分配的成本。

答案 1 :(得分:4)

  

由于我们已经移动了语义,是否已经弃用了std::swap

没有。这是通用版本,但您可以对其进行优化以跳过第三个移动操作。我倾向于将 copy-and-swap 习惯用法与我的班级自定义std::swap结合起来。

这意味着我会:

class Aaaa
{
public:
    Aaaa(); // not interesting; defined elsewhere
    Aaaa(Aaaa&& rvalueRef); // same
    Aaaa(const Aaaa& ref); // same
    ~Aaaa(); // same
    Aaaa& operator=(Aaaa object) // copy&swap
    {
        swap(object);
        return *this;
    }
    void swap(Aaaa& other)
    {
        std::swap(dataMember1, other.dataMember1);
        std::swap(dataMember2, other.dataMember2);
        // ...
    }

    // ...
};

namespace std
{
    template<> inline void std::swap(Aaaa& left, Aaaa& right)
    { left.swap(right); }
}

答案 2 :(得分:0)

这取决于你的类型。

您将把它从x移动到z,从y移动到x,从z移动到y。这是底层表示的三个复制操作(可能只有一个指针,可能更多,谁知道)

现在也许你可以为你的类型创建一个更快的交换(xor交换技巧,内联汇编程序,或者你的底层类型的std :: swap可能更快)。

或许你的编译器也很擅长优化,并且基本上将两种情况都优化到相同的指令中(比如将临时寄存在寄存器中)。

我个人倾向于总是实现一个交换成员函数,它将从几个地方调用,包括移动赋值,但是YMMV。

答案 3 :(得分:0)

这个swap()调用移动构造函数和2个移动赋值。我认为可以为他的特定类型的类编写更高效的swap(),如

class X
{
    int * ptr_to_huge_array;
public:
// ctors, assgn ops. etc. etc.

    friend void swap(X& a, X& b)
    {
        using std::swap;
        swap(a.ptr_to_huge_array, b.ptr_to_huge_array);
    }
};

无论移动构造函数和赋值运算符的实现如何。