供的swap默认实现版本在效率上可以满足你,你就什么都不需要做。任何人尝试对你定义类型的对象进行swap,只要调用默认版本就可以了,这会工作的很好。
其次,如果swap的默认实现在效率上达不到你的要求(通常就意味着你的类或者类模板在使用同指向实现的指针(pimpl idiom)类似的变量),那么按照下面的去做:
- 提供一个public 的swap成员函数,对你的类型的两个对象值可以高效的swap。原因一会解释,这个函数永远不应该抛出异常。
- 在与你的类或模板相同的命名空间中提供一个非成员swap。让它调用你的swap成员函数版本。
- 如果你正在实现一个类(不是一个类模版),为你的类特化std::swap。让他也调用你的swap成员函数版本。
最后,如果你正在调用swap,确保在你的函数中include一个using声明来使得std::swap是可见的,然后调用swap时不要加std命名空间对其进行限定。
8. 最后的警告——不要让成员函数swap抛出异常
我最后的警告是永远不要让swap成员函数版本抛出异常。因为swap的一个最有用的地方就是帮助类(或类模版)提供强有力的异常安全保证。Item 29中有详细解释,其中的技术也是建立在swap成员函数版本不会抛出异常的假设之上的。这个约束只针对成员函数版本!而不针对非成员函数版本,因为swap的默认版本是基于拷贝构造函数和拷贝赋值运算符的,而一般情况下,这两个函数都允许抛出异常。当你实现一个swap的个性化版本,你就不单单提供了对值进行swap的高效方法;你同时提供了一个不会抛出异常的函数。作为通用规则,swap的这两个特性总是会在一起的,因为高效的swap通常是建立在对内建类型进行操作的基础之上的(像底层的指向实现的指针),而内建类型永远不会抛出异常。
9. 总结
- 当使用std::swap对你的自定义类型进行swap时,如果效率不够高,那么提供一个成员函数版本,并确保这个函数不会抛出异常。
- 如果你提供了一个成员函数swap,同时提供了一个非成员swap来调用成员swap。在类(不是模板)上对std::swap进行特化。
- 当调用swap时,使用using std::swap声明,对调用的swap不使用命名空间限定。
- 为用户定义类型全特化std模板没有问题,但永远不要尝试像std中添加全新的东西。