是专门的 std::swap 现在我们已经有了移动语义
Is specializing std::swap deprecated now that we have move semantics?
可能的重复项:
移动语义 == 自定义交换函数过时了?
这是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
会尽可能高效,当然,前提是我的类定义了移动构造函数和移动赋值运算符?
std::swap
的专用化现在是可选的,但未弃用。 基本原理是性能。
对于原型代码,甚至可能对于许多交付代码,std::swap
将非常快。 但是,如果您处于需要从代码中获取每一点的情况,那么编写自定义交换仍然是一个显着的性能优势。
考虑以下情况:您的类基本上有一个拥有指针,而您的移动构造函数和移动赋值只需要处理该指针。 计算每个成员的机器负载和存储:
移动构造函数:1 个加载和 2 个存储。
移动分配:2 个装载和 2 个商店。
自定义交换:2 个加载和 2 个存储。
std::swap
是 1 个移动构造和 2 个移动分配,或:5 个负载和 6 个存储。
自定义交换可能仍然比std::swap
快两到三倍。 尽管任何时候您都试图通过计算负载和存储来计算某物的速度,但两者都会很快变得邪恶。
注意:在计算移动分配的成本时,请确保并考虑到您将移动到移出值(在std::swap
算法中(。 这通常会抵消解除分配的成本,尽管是以分支为代价的。
既然我们有移动语义,是否
std::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); }
}
这将取决于您的类型。
您将它从 x 移动到 z,从 y 移动到x,从 z 移动到 y。这是底层表示的三个复制操作(也许只有一个指针,也许更多,谁知道呢(
现在,也许您可以为您的类型创建一个更快的交换(异或交换技巧,内联汇编器,或者您的底层类型的 std::swap 只是更快(。
或者,也许您的编译器也擅长优化,并且基本上将这两种情况优化为相同的指令(例如在寄存器中具有临时指令(。
我个人倾向于总是实现一个交换成员函数,该函数将从多个位置调用,包括移动分配之类的东西,但是 YMMV。
此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);
}
};
无论移动构造函数和赋值运算符的实现如何。
- 何时在引用或唯一指针上使用移动语义
- 如何从具有移动语义的类对象中生成共享指针
- 可以使用移动语义更改或改进此C++代码吗?
- c++在使用指针时移动语义
- 使用移动和复制语义时函数匹配如何工作?
- 移动语义和深层/浅层复制之间有什么关系?
- 了解构造函数在移动、复制、赋值语义中的行为
- std::unique_lock移动语义
- 移动语义和运算符 + 重载
- C++ 移动语义是否在任何情况下都能节省资源?
- 移动语义在这里如何工作?
- 使用移动语义:右值引用作为方法参数
- 在C++中使用移动语义的正确方法是什么?
- 移动语义 c++ 单链表
- C++:使用整数移动语义
- 当变量和参数名称匹配时,移动语义构造失败
- 在 C++11 中移动语义
- 方法冗余移动调用的移动语义
- 视觉理解移动C++标准的语义
- 如何通过move语义移动多个参数