A.15. std::exchange() 原子交换

<utility> 头文件中隐藏着(至少)两个非常有用且基础的函数。其中一个广为人知,并且已经存在了很长时间:std::swap(),它在标准库以及用户代码中广泛用于各种目的。

另一个是较新加入的函数:std::exchange()。swap(a, b) 的作用是交换对象 a 和 b 的值;而表达式 a = exchange(b, c) 的作用是将 b 的值用 c 替换,并返回 b 的旧值(然后赋值给 a)。这在一开始看起来可能有些奇怪,但它实际上是一个非常有用的工具。

举个例子,考虑以下简化版的 fixed_size_array 的移动构造函数:

template <class T>
class fixed_size_array {
  T *elems{};
  std::size_t nelems{};
public:
  // ...
  fixed_size_array(fixed_size_array &&other)
    : elems{ other.elems }, nelems{ other.nelems } {
    other.elems = nullptr;
    other.nelems = 0;
  }
  // ...
}

这个构造函数做了两件事:它从 other 中获取数据成员,然后将 other 的成员替换为默认值。这正是 std::exchange() 的典型用例,因此这个构造函数可以简化为如下形式:

template <class T>
class fixed_size_array {
  T *elems{};
  std::size_t nelems{};
public:
  // ...
  fixed_size_array(fixed_size_array &&other)
    : elems{ std::exchange(other.elems, nullptr) },
    nelems{ std::exchange(other.nelems, 0) } {
  }
  // ...
}

通过使用 std::exchange(),这种常见的两步操作可以简化为一次函数调用,使代码更加简洁,并且效率更高(在本例中,将赋值操作变为了构造调用)。