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. 爬虫 (6)- Scrapy 实战案例 - 爬取不锈钢的相关钢卷信息

    超详细创建流程及思路 一. 新建项目 1.创建文件夹,然后在对应文件夹创建一个新的python项目 2.点击Terminal命令行窗口,运行下面的命令创建scrapy项目 scrapy startpr ...

  2. ansible分发密钥

    http://www.361way.com/ansible-cfg/4401.html 修改host_key_checking(默认是check的):改为false,      host_key_ch ...

  3. ssd算法论文理解

    这篇博客主要是讲下我在阅读ssd论文时对论文的理解,并且自行使用pytorch实现了下论文的内容,并测试可以用. 开篇放下论文地址https://arxiv.org/abs/1512.02325,可以 ...

  4. R语言安装sqldb包报错解决办法

    我使用Rtudio环境,安装sqldb几次出错.网上没有好的教程. 经过自己试验之后,这样处理.我写出来以后,供大家参考. > install.packages("sqldf" ...

  5. Apple设备中point,磅(pt),pixel的关系与转换,以及iPhone模拟器与真机的长度关系

    查阅了好多资料都没有发现有相关的详细介绍,包括苹果官方文档,也是草草带过.后来是在一个介绍Macbook打印字体的博客中看到的,受到启发. 首先说明苹果设备绘图的长度单位可以认为是point,不是磅( ...

  6. EasyUI简单CRUD

    <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head>    < ...

  7. Java入门 第一季第六章 数组

    这是我学习慕课网Java课程的笔记,原视频链接为:http://www.imooc.com/learn/85 6-1什么是数组 数组中的元素都能够通过下标来訪问.下标从 0 開始.比如,能够通过 sc ...

  8. uva 465 - Overflow 高精度还是浮点数?

    uva 465 - Overflow  Overflow  Write a program that reads an expression consisting of two non-negativ ...

  9. ChemDraw综合型化学工具你值得拥有

    1.ChemDraw综述 ChemDraw是业界领先的科学分析桌面套件,ChemDraw基础功能包括编辑.绘制与化学有关的一切结构图形,如建立和编辑各类分子式.方程式.结构式.立体图形.对称图形.轨道 ...

  10. 用原生JS模仿jquery,需要HTML5的支持

    jQuery是现在最流行的JavaScript工具库. 据统计,目前全世界57.3%的网站使用它.也就是说,10个网站里面,有6个使用jQuery.如果只考察使用工具库的网站,这个比例就会上升到惊人的 ...