item 25:一个不抛异常的swap函数

标准库有一个swap用于交换两个对象值

namespace std{

template<typename T>

void swap(T& a , T& b)

{

T temp(a) ;

a = b ;

b = temp ;

}

}

所以,只要对象的类型T支持copying(copy ctor 和 copy assignment),那么你就可以用这个标准库的swap,但是,你必须保证,你swap的时候,上述操作是你需要的,有的时候,没有必要,尤其是pimpl(pointer to implementation)手法。

例如下面这个例子:

class WidgetImpl{

public :

....

private :

int a , b , c  ;

....   //好多成员

};

class Widget

{

public:

Widget(const Widget & rhs) ;

Widget& operator=(const Widget & rhs)

{

*pImpl = *rhs.pImpl // 复制所指的对象

}

private:

WidgetImpl * pImpl ;

};

一旦要交换两个Widget,我们其实就让两个指针换一下就可以了,没有必要把指针所指的内容互换,那样效率太低。

想法1:

namespace std{

template<>  // 全特化

void swap<Widget> (Widget & a,  Widget & b)

{

swap(a.pImpl , b.pImpl) ;

}

}

上面这个想法编译不过,因为pImpl是private的,是不能被外界访问的。

想法2 : 加入类的成员函数swap,让模板函数去调用

class Widget{

public :

void swap(Widget & other)

{

using std::swap ;  // 后面讲

swap(p.Impl , other.pImpl) ;

}

...

};

namespace std{

template<>  // 全特化

void swap<Widget> (Widget & a,  Widget & b)

{

a.swap(b) ;

}

}

通过上面的写法,我们就能得到正确的,针对类别Widget 的swap函数。这就叫为你的class特化std::swap,并令它调用你的swap函数。

但是,问题,如果我现在是类模板,怎么办?

现在的类是:

template<typename T>

class WidgetImpl{...}

template<typename T>

class Widget{...}

如果你现在这么做:

namespace std{

template<typename T>  // 偏特化

void swap<Widget> (Widget<T> & a,  Widget<T> & b)

{

a.swap(b) ;

}

}

sorry不行了,原因有以下2点:

1、因为C++只允许对class template进行偏特化,不对能function template进行偏特化。

2、在std这个命名空间,不可以添加新的template到std里。上面,我们能加东西到std是因为,为标准的templates(eg : swap)制造特化版本。

为了解决上述2两个问题,引入下面的解决方法

想法3:转为class template量身打造

定义一个专门的命名空间,放入我们所有的东西

namespace WidgetStuff{

template<typename T>

class WidgetImpl{...}

template<typename T>

class Widget{...} // 这个里面有一个swap函数

template<tyoename T>

void swap(Widget<T>& a , Widget<T>& b)

{

a.swap(b) ;

}

}

我们在用swap函数的时候,应该这么用:

template<typename T>

void doSomething(T& obj1 , T& obj2)

{

using std::swap ;  // 这样即使没有T的专属版本的swap函数

swap(obj1 , obj2)  ;

}

上面就结束了我们swap函数的制作过程,那么为什么可行呢?这个都是利用了C++的名称查找规则

编译器用“实参取决之查找规则”,找出WidgetStuff中的swap函数,如果命名空间中没有T的专属swap函数,编译器就用std::swap,即使如此,编译器还是喜欢std::swap重T的专属版本,就是想法2会选中。所以,优先级顺序是想法3--》想法2--》标准库自己的swap

总结:

1、弄清楚什么时候我们需要自己写swap函数

2、在class 或者 class template提供一个public swap函数

3、在class 或者 class template的命名空间中提供一个non-member swap ,调用2中的swap

4、如果你正在编写一个class(不是template),为class特化std::swap。并令他调用2中的swap

5、当你实际用swap时,先using std::swap,然后不加任何修饰符,赤裸裸调用swap

成员版swap决不能抛出异常,因为很多异常安全性代码都是通过类的swap成员函数保证的,并且,我们自己去写swap,一般都是用指针,内置类型,这些类型不会抛异常,写swap是为了高效

effective C++ 条款25 swap的更多相关文章

  1. Effective C++ -----条款25:考虑写出一个不抛异常的swap函数

    当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异常. 如果你提供一个member swap,也该提供一个non-member swap用来调用前者.对于cla ...

  2. [More Effective C++]条款22有关返回值优化的验证结果

    (这里的验证结果是针对返回值优化的,其实和条款22本身所说的,考虑以操作符复合形式(op=)取代其独身形式(op),关系不大.书生注) 在[More Effective C++]条款22的最后,在返回 ...

  3. More Effective C++ 条款0,1

    More Effective C++ 条款0,1 条款0 关于编译器 不同的编译器支持C++的特性能力不同.有些编译器不支持bool类型,此时可用 enum bool{false, true};枚举类 ...

  4. Effective C++:条款25:考虑写出一个不抛异常的swap函数

    (一) 缺省情况下swap动作可由标准程序库提供的swap算法完毕: namespace std { template<typename T> void swap(T& a, T& ...

  5. 读书笔记 effective c++ Item 25 实现一个不抛出异常的swap

    1. swap如此重要 Swap是一个非常有趣的函数,最初作为STL的一部分来介绍,它已然变成了异常安全编程的中流砥柱(Item 29),也是在拷贝中应对自我赋值的一种普通机制(Item 11).Sw ...

  6. EC读书笔记系列之13:条款25 考虑写出一个不抛异常的swap函数

    记住: ★当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定其不抛出异常 ★若你提供一个member swap,也该提供一个non-member swap来调用前者.对于cla ...

  7. 条款25:考虑写出一个不抛出异常的swap函数

    首先说下标准库的swap算法: namespace std{ template<typename T> void swap(T & a, T & b) { T tmp = ...

  8. Effective C++ Item 25 考虑写出一个不抛异常的swap函数

    本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛 ...

  9. Effective C++ 条款08:别让异常逃离析构函数

    1.别让异常逃离析构函数的原因 <Effective C++>第三版中条款08建议不要在析构函数中抛出异常,原因是C++异常机制不能同时处理两个或两个以上的异常.多个异常同时存在的情况下, ...

随机推荐

  1. ID4收藏

    IdentityServer4.Admin https://github.com/skoruba/IdentityServer4.Admin

  2. cocos2d-x 输入框CCEditBox的使用

    特别说明: 这个版本的CCEditBox,设计有缺陷,背景图片的位置与输入区域的位置不同步,需要自己修改原来的代码,自己加上输入区域的坐标偏移量. void CCEditBox::setPositio ...

  3. cocos2dx3.1 win7安装步骤及编译到安桌

    1. 下载及安装好工具 python2.7  ndk sdk ant cocos2dx3.1 eclipse 这些工具和曾经一样下载好放到同一文件夹下 加入环境变量 将python2.7的安装路径加入 ...

  4. H.264 Profile

    提到High Profile H.264解码许多人并不了解,那么到底什么是High Profile H.264解码?其应用效果又是如何呢?  作为行业标准,H.264编码体系定义了4种不同的Profi ...

  5. 再谈Unity调用Android的Activity

    这段时间在研究Unity4.3开发环境下.怎样调用由Android SDK4.4.2写的Activity.參考了非常多网上的博客.百度出了几十篇大部分都是转载雨松MOMO的,这里必须向雨松MOMO表示 ...

  6. java网络编程2-URL和URI

    //创建url可以指定请求的url协议,但不同的jvm支持的协议可能不相同(大部分支持http.file.https) //构造只判断字符串中的协议支不支持,而不判断url的正确性 URL url=n ...

  7. 努比亚Z18mini多点对焦

    25点对焦 分为了中心对焦.中间对焦.边缘对焦三个区域 [参考文献] 手机上感受单反的“多点对焦”努比亚Z18mini给你想象 https://baijiahao.baidu.com/s?id=160 ...

  8. pocket

    Pocket是一个离线阅读服务软件. Pocket的主要功能就是将你要阅读或者一时没有读完的网页标记下来,接着同步到服务器端,然后你就可以在不同的设备上阅读.如果你在电脑上网的时间不多,一些东西又来不 ...

  9. 2154: Crash的数字表格

    2154: Crash的数字表格 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 3372  Solved: 1258[Submit][Status][ ...

  10. 解决jsp上传文件,重启tomcat后文件和文件夹自动删除

    吼吼,我遇到的问题是这样的......我写了一个图片上传的方法,上传时,判断没有这个目录就自动建立一个.然后开始上传图片,能成功,能在服务器找到文件夹和相应的文件. 但是,重启项目,或者清理缓存之后, ...