条款25:考虑写出一个不抛异常的swap函数
Consider support for a non-throwing swap.
本章作为设计与声明最后一章,内容较长,分为三部分。
swap
swap是一个有趣的函数。
原本它只是STL的一部分,而后则成为异常安全性编程(exception-safe programming)的主体,以及后来用于处理自我赋值可能性(条款11)的一个常见机制。因此,swap的实现是非常重要的。
swap的缺省实现
所谓的swap(置换)两对象的值,指的就是将两对象的值彼此赋予对方。在默认的情况之下,swap动作可以由STL提供的swap算法来实现:
namsespace std {
tempate<typename T>
void swap(T& a, T& b)
{
T temp(a);
a = b;
b =temp;
}
}
只要类型T支持copying(通过copy构造函数和copy assignment操作符来完成),缺省的swap实现代码就会自动置换类型为T的对象,我们并不需要额外的工作。
这种缺省的实现比较简单,涉及到了三个对象的复制:
- a复制到temp
- b复制到a
- temp复制到b。
但是对于某些类型而言,这些复制动作并没有必要!
其中最主要的即“以指针指向一个对象,内含真正数据”的类型。
这种类型最常见的表现形式就是“pimpl手法”(pointer to implementation)
如果以这种手法设计Widget class:
class WidgetImpl {
public:
...
private:
int a, b, c; //可能有许多数据,意味着复制时间很长
std::vector<double> v;
...
};
class Widget { //该class使用pimpl手法
public:
Widget(const Widget& rhs); //复制Widget时,令它复制其WidgetImpl对象
Widget& operator=(const Widget& rhs) //operator=的实现见条款10~12
{
...
*pImpl = *(rhs.pImpl);
...
}
...
private:
WidgetImpl* pImpl; //指针,所指的对象就是内含Widget数据
};
一旦我们需要置换两个Widget对象的值,我们唯一需要做的就是置换其pImpl指针而已。
但是,缺省的swap并不知道这一点!它不仅会复制三个Widgets,还会复制三个WidgetImpl对象!效率一下子就变得很低了。