首先说下标准库的swap算法:

 namespace std{
template<typename T>
void swap(T & a, T & b)
{
T tmp = a;
a = b;
b = tmp;
}
}

显然的,标准库实在是索然无味,自己随便写都能写出来,而且这样写有时候对于某些来说效率是特别低的。看看下面这个这个例子:

 class WidgetImpl{
public:
...
private:
int a, b, c;
std::vector<double> v;
...
};
class Widget{
pubcic:
Widget(const Widget & rhs);
Widget & operator=(const Widget & rhs)
{
...
*pImpl = *(rhs.pImpl);
...
}
private:
WidgteImpl * pImpl;
};
这个operator=配上上面那个swap一起的效率便非常的地下,本来交换Widget中Impl两者的指针就可以很高效的完成swap操作,但是这里硬是活生生的拷贝了两个对象。
那么怎么完成高效的swap函数呢,首先想到的可能就是将标准库中的swap特例化,像下面这样:
 namespace std{
template<>
void swap<Widget>(Widget & a, Widget & b)
{
swap(a.Impl, b.Impl);
}
}

上面这个swap是标准库swap的total template specialization版本,但是他并不能通过编译,原因是因为其访问了对象的私有函数。正确的做法一般是下面这样:

 class Widget{
public:
...
void swap(Widget & other){
using std::swap;
swap(pUmpl, other.pUmpl);
}
...
};
namespace std{
template<>
void swap<Widget>(Widget & a, Widget & b)
{
a.swap(b);
}
}
上面的做法与STL标准库也是高度一致,标准库的容器也都是有std版本的swap而且都在自己内部空间实现了swap供给前者调用。
但是上述的做法在Widget是类模板的时候就不起作用了。因为下面的式子:
namespace std{
template<typename T>
void swap<Widget<T> >(Widget<T> & a, Widget<T> & b)
{
a.swap(b);
}
}
被c++规定为非法的。
所以所,在无法进行模板特例化的情况下,就需要在特定的自己定义的名字空间创造一个swap函数(或者在std空间中重载一个版本,但是c++是不允许那样做的)。那么据类似下面这样:
 namespace WidgetStuff{
...
template<typename T>
class Widget{.......};
...
template <typename T>
void swap(Widget <T> & a, Widget<T> & b)
{
a.swap(b);
}
}
这样就大功告成了。。
这样,在任何的位置调用有关Widget的swap的时候,就会首先在WidgetStuff的名字空间里面寻找相应的swap。
注意Widget的成员函数版本的swap中有一行是加上了下划线的,这个using声明语句的作用是即使当这个名字空间中的swap对Impl不能起到作用的时候,至少可以让Impl可以借助于std::swap来完成交换的操作。
 
总结一下:
如果因为系统默认版本的swap效率不足话,那么就要做下面这几件事:
    1. 提供一个class public swap对象,使其高效的置换两个特殊对象的值
    2. 在这个class或者template所在的命名空间提供一个non-memberswap,作用是来调用上述的
    swap.
    3.如果上述的class或者class template实际上是个class而非template,最好是特例化std::swap
    ,并且用这个来调用member的swap函数。
    4.在使用swap的时候,尤其是在自己定义的命名空间下,记得使用一个using 声明吧std::swap包含进来,这样即使在本命名空间中找不到合适的swap,至少也可以调用std的swap.且使用swap的时候不要再前面加上名字空间声明,这样前面声明的std::swap就白做了
 
注意,成员版本的swap绝对不能抛出异常,但是非成员版本的swap函数是允许抛出异常的。前者不抛出异常的原因是其往往是针对内置类型的操作,而内置类型的操绝对不允许抛出异常。
 

条款25:考虑写出一个不抛出异常的swap函数的更多相关文章

  1. 读书笔记_Effective_C++_条款二十五: 考虑写出一个不抛出异常的swap函数

    在之前的理论上调用对象的operator=是这样做的 void swap(A& x) { std::swap(a, x.a); } A& operator=(const A& ...

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

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

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

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

  4. 考虑写一个不抛出异常的swap函数

    我们可以调用std下的swap函数,这是一个模板函数:既可以: ; ; std::swap(a,b); cout<<"a = "<<a<<&qu ...

  5. 输入一个数字n 如果n为偶数则除以2,若为奇数则加1或者减1,直到n为1,求最少次数 写出一个函数

    题目: 输入一个数字n  如果n为偶数则除以2,若为奇数则加1或者减1,直到n为1,求最少次数  写出一个函数 首先,这道题肯定可以用动态规划来解, n为整数时,n的解为 n/2 的解加1 n为奇数时 ...

  6. java————数组 简单写出一个管理系统

    数组的特点 1,  数组是一块连续的空间,下标描述空间的位置. 2,  下标从0开始,最大下标为数组长度—1.(*.length-1) 3,  数组元素都是变量.(就是每个下标对应的内容).变量的类型 ...

  7. 如何写出一个让人很难发现的bug?

    程序员的日常三件事:写bug.改bug.背锅.连程序员都自我调侃道,为什么每天都在加班?因为我的眼里常含bug. 那么如何写出一个让(坑)人(王)很(之)难(王)发现的bug呢? - 1 -新手开发+ ...

  8. 浅谈如何写出一个让(坑)人(王)很(之)难(王)发现的bug

    该文章内容来自脚本之家,原文链接:https://www.jb51.net/news/598404.html 程序员的日常三件事:写bug.改bug.背锅.连程序员都自我调侃道,为什么每天都在加班?因 ...

  9. 请写出一个超链接,点击链接后可以向zhangsan@d-heaven.com发送电子邮件。

    请写出一个超链接,点击链接后可以向zhangsan@d-heaven.com发送电子邮件. <a href=”mailto: zhangsan@d-heaven.com”>发邮件</ ...

随机推荐

  1. Dom4j总结

    1.DOM4J简介 DOM4J是 dom4j.org 出品的一个开源 XML 解析包.DOM4J应用于 Java 平台,采用了 Java 集合框架并完全支持 DOM,SAX 和 JAXP. DOM4J ...

  2. 商业模式画布模板——From 《商业模式新生代》

    看过<商业模式新生代>这本书,确实受益匪浅.书籍本身编写的形式很新颖,以此为模板可以启发自己对于商业模式的思考和定义,五星推荐!!! 下面是用PPT重新绘制的商业模式画布以及说明,希望对大 ...

  3. 对ASIHTTPRequest的封装

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/quanqinayng/article/details/37659751 .h文件  // // Ht ...

  4. android studio中取消关联git

    Android studio取消关联Git 步骤如下 settings->version control 这里是已经取消关联的 如果关联 按住减号即可

  5. PAT 1035 Password [字符串][简单]

    1035 Password (20 分) To prepare for PAT, the judge sometimes has to generate random passwords for th ...

  6. 用python简便地抓取刘昊然的写真(17行代码)

    17行python代码抓取刘昊然图片之家的写真 用python来爬取网页信息是很简便的.因为它有很多库来帮助我们实现我们想要的功能.本实验用到的库有:requests和bs4中的BeautifulSo ...

  7. Flume日志收集 总结

    Flume是一个分布式.可靠.和高可用的海量日志聚合的系统,支持在系统中定制各类数据发送方,用于收集数据: 同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力. (1) 可靠 ...

  8. java 获取request参数集

    request里有两个方法 request.getParameterMap(); request.getParameterNames(); 我想用这两种方法获取. 1.用request.getPara ...

  9. Alluxio 安装与配置

    一.概述 Alluxio, formerly Tachyon, enables any application to interact with any data from any storage s ...

  10. Storm--命令行解析

    strom的命令行解析 Commands: activate classpath deactivate dev-zookeeper drpc help jar kill list localconfv ...