如何正确地为 C++ Class 实现 swap 函数?

2023-08-19 C++

如何为你自己的 Class 实现 swap 功能?有三种方法都能完成这个功能,包括:

  1. 以成员函数的形式实现 swap;
  2. std::swap 函数模板进行特化;
  3. 以非成员 friend 函数的形式实现 swap。

第三种方法是最好的。本文将逐个介绍三种方法,以说明为什么第三种方法是最值得推崇的。

1. 成员函数形式的 swap

这种形式的 swap 在标准库中就有,比如 std::vector 拥有如下成员函数:

void vector::swap(vector& x);

但这并不意味着这就是标准做法。实际上,这种方法不好。因为通常来说,当用户想要交换两个对象时,首先会想到使用 std::swap。而上述这种 swap 成员函数无法被 std::swap 利用到

这就引出了第二种实现 swap 的方法:对 std::swap 函数模板进行特化。

2. 对 std::swap 进行特化

具体方法为:

namespace std
{
    template <>
    void swap(MyClass&, MyClass&)
    {
        // swap
    }
}

但这种方式有一个致命伤:不能针对 Class Templates 进行特化,因为在 C++ 中函数模板只能进行全特化,不支持部分特化(Partial Specialization):

namespace std
{
    template <typename T>
    void swap<T>(MyClass<T>&, MyClass<T>&) // error! no partial specialization
    {
        // swap
    }
}

因此,这种方法也不通用。这就引入第三种方法:以友元函数的方式实现 swap。

3. 以友元函数的方式实现 swap

具体方式为:

struct MyClass {
    friend void swap(MyClass&, MyClass&) {
				// swap
		}
};

然后在调用的时候,用户可以利用 ADL (Argument-dependent lookup) 自动匹配合适的 swap 实现:

using std::swap; // 将 std::swap 暴露到当前 namespace
swap(x, y);      // 如果 x, y 的 Class 定义了 swap,则使用它们。否则,使用 std::swap

这种方式最为通用,例如在经典的 Copy-and-Swap 惯用法中实现 swap 就使用了这种方式。

参考