什么时候在 C++ 中提供自定义交换功能?

When to provide custom swap function in C++?

考虑使用移动构造函数 (MC)、移动赋值运算符 (MAO) 和自定义交换来保存一些资源(为简单起见,此处用整数成员变量表示)的自定义 class X功能:

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_; }
};

在以下基准代码中:

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();
}
  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、swapstd::swap 的所有功能都 直接内联到 main(gcc/clang 带有 -O2 标志)。此外,程序中没有创建 X 类型的对象,它仅适用于机器代码级别的整数。

因此,在我看来,没有理由为像 X 这样的 class 提供自定义 swap 函数。

问题:

  1. 假设编译器将优化 MC 和 std::swap 内部的 MAO/UAO 调用是一种好习惯吗?或者,我应该为所有自定义 class 定义自定义 swap 吗?
  2. 自定义 swap 对哪些 classes 真的有益?

你应该遵循0的规则。

非资源管理 类 应具有默认值 move/copy/assign/destruction。

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

您的代码不管理资源。 copy/move 明智的一切都应该默认。

swap 是 move 的特例。如果您是资源管理类型,您可能还想编写它。但是,与大多数事情一样,它是一种优化,只有在证明它对性能有影响的情况下才应该进行此类优化。

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

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

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