Item 25 不应抛出异常的swap

来源:互联网 发布:视频缩略图软件 编辑:程序博客网 时间:2024/06/06 20:22

通用的swap可以在stl里找到:

 

 

有很多类使用pimpl来分离实现与接口,对它们的swap要慎重。

 

 

其实,swap只要交换二者的指针即可,不用拷贝里面的数据:

 

 

STL里的容器都是这样实现swap的。

现在假设Widget和WidgetImpl都是模板类,即:

 

 

那么,如何实现swap呢?下面这样的思路可以吗:

 

 

实际上,对模板函数的定义进行“partial specialization”在C++中是无效的。如果编译通过,说明编译器有问题。
不过,对模板类,可以进行“partial specialization”。

那么,重载swap可以解决问题吗:

 

 

但是,std这个名字空间,是不适合用上面的方法解决问题的。这属于对std空间增加了新的模板类。
而std空间的内容,只有C++委员会才有权决定。
可能上面的代码在一些编译器上可以正常运行,比如VC,但实际上属于“未定义行为”!

需要稍稍改一下:

 

 

把swap移到新的名字空间了。那么,像下面的代码:

 

 

C++将应用argument-dependent lookup (Koenig lookup)规则,进行查找,最后找到以Widget作为参数的swap函数。

从客户的角度看下面的代码:

 

 

哪一个swap会被调用到呢?有可能是std里的通用版本;有可能是std里完全特化的版本;有可能是在某个名字空间里的重载版本。
如果你想让它调用重载版本,当重载版本不存在,就调用std通用版本,那么可以像下面这样写:

 

 

C++查找swap的规则是:先在全局名字空间中找,然后在T的名字空间中找。
在std中,C++优先使用特化的版本,如果该版本存在的话。

有些程序员喜欢这样写:

std::swap(obj1, obj2);

这样就限制了swap的查找。
为了帮助这样的代码也能提高效率,你要在你的类里,定义特化的版本。

基于对“异常安全”的考虑,swap成员函数不应该抛出异常。只有这样,swap才能做到异常安全。
swap的行为基于copy ctor和拷贝赋值。这两个函数可以抛出异常。
自定义swap是为了更高的效率,应该只处理内建类型,所以不应该抛出异常。

原创粉丝点击