Effective C++读书笔记(16)
来源:互联网 发布:淘宝良心二手手机店铺 编辑:程序博客网 时间:2024/06/10 19:37
条款25:考虑写出一个不抛出异常的swap函数
swap函数是异常安全性编程的脊柱,以及用来处理自我赋值可能性的一个常见机制。
缺省情况下,swap动作可由标准程序库提供的swap算法完成。(对象需要支持copying函数)
namespace std{template <typename T>void swap(T& a, T& b){ T temp(a); a = b; b = temp;}这种方法效率较低,需要将对象进行三次复制运算,每次运算都复制里面的每个成员变量。改进方法:采用“pimpl方法”(pointer to implementation),定义一个专门封装真正数据的类,然后原有类别包含一个指针指向该数据类。
class WidgetImpl { //针对Widget数据设计的classpublic: ....private: int a,b,c; //包含Widget的数据 std::vector<double> v; .....};class Widget {public: Widget(const Widget& rhs); Widget& operator=(const Widget& rhs) { ... *pImpl = *rhs.pImpl;//进行深度拷贝,将指针内的数据进行复制 ... } ...private: WidgetImpl* pImpl;};
一旦要置换两个Widget对象值,我们唯一需要做的就是置换其pImpl指针,但是缺省的swap算法不知道这一点。它仍然复制pImpl所指对象的所有内容,所以我们应该将std::swap针对Widget特化,但是因为swap函数要访问Widget里面的private成员,因此我们可以将这个特化版本声明为friend,但是这个版本的特化和以往的规则不同:在类中声明一个public成员函数做真正的置换工作,然后将std::swap特化,让其调用该成员函数(这种做法不仅可以实现功能,还可以跟STL容器有一致性,因为所有STL容器也都提供有public swap成员函数和std::swap特化版本):
class Widget {public: ... void swap(Widget& rhs) { using std::swap; //这个声明的必要性稍后解释 swap(pImpl, rhs.pImpl); } ...};namespace std { template <> void swap<Widget> (Widget& a, Widget& b) //特化版本 { a.swap(b); }}
template <typename T>class WidgetImpl {....};template <typename T>class Widget {.......};如果像以往一样进行特化会生成对函数的偏特化。
namespace std { template<typename T> void swap< Widget<T> >(Widget<T>& a, Widget<T>& b) { a.swap(b);}}
C++只允许对class templates偏特化,在function templates上偏特化是行不通的。(当打算偏特化一个函数模版时,常用做法是简单的为他添加一个重载模版版本)
namespace std { template<typename T> void swap(Widget<T>& a, Widget<T>& b) { a.swap(b);}}
但是,std是个特殊的命名空间,其管理规则也比较特殊。客户可以全特化std内的templates,但不可以添加新的templates(classes或者functions或其他任何东西)到std里面。因此,我们的做法是我们还是声明一个non-member swap让它调用member swap,但不再将那个non-member swap声明为std::swap的特化版本或者重载版本,而是将其放在另一个命名空间内。
namespace WidgetStuff { ... template<typename T> class Widget {...}; ... template<typename T> void swap(Widget<T>& a, Widget<T>& b) { a.swap(b); }}
现在,任何地点的任何代码如果打算置换两个Widget对象,因而调用swap,C++的名称查找法则会找到WidgetStuff内的Widget专属版本。
如果你想让你的“class专属版”swap在尽可能多的语境下被调用,你需要同时在该class所在的命名空间内些一个non-member版本以及一个std::swap特化版本(为了让std::swap特化版本被发现,所以应该如前述代码一样加上using std::swap)。
总结:首先,如果swap的缺省实现码对你的class或者class template提供可接受的效率,你不需要额外做任何事。任何尝试置换(swap)那种对象的人都会去的缺省版本,而那将会有良好的运作。
其次,如果swap缺省实现版的效率不足(那几乎总是意味着你的class或者template使用了某种pimpl手法),试着做以下事情:
1.提供一个public swap成员函数,让你高效地置换你的类型的两个对象值。2.在你的class或者template所在的命名空间内提供一个non-member swap,并令其调用swap成员函数。3.如果正编写一个class(而非class template),为你的class特化std::swap,并令它调用你的swap成员函数。
最后,如果你调用swap,请确定包含一个using声明式,以便让std::swap在你的函数内曝光可见,然后不加任何namespace修饰符,赤裸裸的调用swap。
成员版swap绝不可抛出异常。因为swap的一个最好的应用是帮助classes提供强烈的异常安全性保障。这一技术基于一个基础:成员版swap绝不抛出异常。
- 《Effective C++》读书笔记
- 《Effective C++》读书笔记
- 《Effective c++》读书笔记
- 《more effective c++》读书笔记
- <<effective c++>> 读书笔记
- 《Effective C++》读书笔记
- 《Effective C++》读书笔记
- Effective C++(1)读书笔记
- Effective C++(2)读书笔记
- 《Effective C++》读书笔记
- 《Effective C++》读书笔记
- 《effective c++》读书笔记【一】
- 《effective c++》读书笔记1
- 《effective c++》读书笔记2
- 《effective c++》读书笔记3
- 《effective c++》读书笔记4
- 《effective C++》读书笔记
- Effective C++-读书笔记
- 读书笔记--中国哲学史大纲--2014年02月18日
- PPTP - GRE
- hdu 1561 The more, The Better (树形dp)
- Android项目使用Ant打包,自动生成build.xml
- 刀片服务器和磁盘阵列卡(RAID)技术---永和维护
- Effective C++读书笔记(16)
- MySql 8小时解决方案:proxool连接池
- DSP 之实时时钟(RTC)编程
- mount umount(挂载)命令详解
- struts标签处理map中包含list 展示
- jasper报表the document has no pages的问题解决
- http://www.cnblogs.com/strivers/archive/2011/02/06/1949477.html
- as3 小知识点
- C写的单向链表List操作函数