何时在 C++ 中提供自定义交换函数?

Dan*_*ica 3 c++ swap move-semantics c++11

考虑一个自定义类,X其中包含一些资源(为了简单起见,这里用整数成员变量表示),其中包含移动构造函数 (MC)、移动赋值运算符 (MAO) 和自定义交换函数:

class X {
  int i_;
public:
  X(int i) : i_(i) { }
  X(X&& rhs) = default; // move constructor 
  X& operator=(X&& rhs) = default; // move assignment operator 
  // X& operator=(X rhs) { std::swap(i_, rhs.i_); return *this; } // unifying assign. op.
  friend void swap(X& lhs, X& rhs) { std::swap(lhs.i_, rhs.i_); }
  int i() const { return i_; }
};
Run Code Online (Sandbox Code Playgroud)

在以下基准代码中:

int main() {
  int i1, i2;
  std::cin >> i1 >> i2;

  X x1(i1), x2(i2);
  std::cout << x1.i() << x2.i();

  swap(x1, x2);
  std::cout << x1.i() << x2.i();

  std::swap(x1, x2);
  std::cout << x1.i() << x2.i();
}
Run Code Online (Sandbox Code Playgroud)
  1. swap(x1, x2)只需交换 2 个整数即可。
  2. std::swap(x1, x2) 调用 1x MC 和 2x MAO
  3. 如果 MAO 被统一赋值运算符 (UAO) 替换,std::swap(x1, x2) 则调用 3x MC 和 2x UAO

(使用 gcc/libstdc++ 测试)。

看起来,自定义swap非常有价值,因为它避免了许多函数调用。然而,当我查看该程序的分解输出时:https://godbolt.org/g/RMfZgL,MC、MAO、UAO的所有功能swap直接内联到std::swap(带标志的 gcc/clang )中。此外,程序中不会创建任何类型的对象,它仅适用于机器代码级别的整数。main-O2X

因此,在我看来,没有理由为swapX.

问题:

  1. 假设编译器会优化内部 MC 和 MAO/UAO 的调用,这是一个好习惯吗std::swap?或者,我应该swap为所有自定义类定义自定义吗?
  2. 定制对于哪些类型的课程swap真正有益?

Yak*_*ont 5

你应该遵循0的规则。

非资源管理类应该有默认的移动/复制/分配/销毁。

资源管理类应该只关心管理资源。

您的代码不管理资源。一切复制/移动都应该默认。

swap是移动的一个特例。如果您是资源管理类型,您可能也想编写它。然而,像大多数事情一样,它是一种优化,只有在证明它对性能有影响时才应该进行此类优化。

它可能会对性能产生影响的一个例子是,如果您有一个永不为空的资源拥有类型,并且该资源不是免费的,那么创建临时对象会产生不可避免的成本。 std::swap默认情况下,移动穿过一次性对象。自定义交换可以避免这种情况。

或者,一种类型,它是一个大缓冲区,可以廉价地移动元素;创建如此大的缓冲区可能会产生实际成本。

否则,不要这样做。并测试一下你是否这样做会有帮助。自定义交换是针对特定情况的移动优化。