Effective C++读书笔记(16)

发布时间:2016-12-9 0:30:07 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Effective C++读书笔记(16)",主要涉及到Effective C++读书笔记(16)方面的内容,对于Effective C++读书笔记(16)感兴趣的同学可以参考一下。

条款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数据设计的class public: .... 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); } } 然而如果Widget和WidgetImpl都是class template, 而不是 class时,即 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绝不抛出异常。

上一篇:刀片服务器和磁盘阵列卡(RAID)技术---永和维护
下一篇:C# 跨线程调用窗体控件

相关文章

相关评论