这就是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
会尽可能高效,前提是我的类定义了移动构造函数和移动赋值运算符吗?
答案 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);
}
};
无论移动构造函数和赋值运算符的实现如何。