2023-08-19
C++
如何为你自己的 Class 实现 swap 功能?有三种方法都能完成这个功能,包括:
- 以成员函数的形式实现 swap;
- 对
std::swap
函数模板进行特化; - 以非成员 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 就使用了这种方式。