swap函数是c++中一个常用的函数,用于交换两对象的值,此外还用于在重载赋值运算符中处理自赋值情况和进行异常安全性编程(见下篇),标准模板库中swap的典型实现如下:

 namespace stl
{
template <typename T>
void Swap(T &lhs, T &rhs)
{
T temp(lhs);
lhs = rhs;
rhs = temp;
}
}

缺省版本的Swap函数包含三次对象的复制:lhs复制到temp,rhs复制到lhs,temp复制到rhs。然而在一些情况下,这种复制是无意义的,这会使得缺省版本Swap函数的效率低下,一种典型的情况出现在使用pimpl方法时:

——pimpl全称为pointer to implementation,即一个指针指向的对象包含真正的数据,例如:

 namespace jz
{
class PersonImpl
{
public:
PersonImpl(const std::string &name_, uint8_t sex_, uint8_t age_, const std::initializer_list<int> &int_il_)
: name(name_), sex(sex_), age(age_)
{
i_vec.assign(int_il_.begin(), int_il_.end());
}
//
PersonImpl(const PersonImpl &rhs)
: name(rhs.name), sex(rhs.sex), age(rhs.age), i_vec(rhs.i_vec)
{ }
//
PersonImpl& operator=(const PersonImpl &rhs)
{
name = rhs.name;
sex = rhs.sex;
age = rhs.age;
i_vec = rhs.i_vec;
}
private:
std::string name;
uint8_t sex : ; //标准没有规定char一定是8-bit,使用8-bit的unsigned int类型,需要包含<cstdint>
uint8_t age : ; //使用位域
std::vector<int> i_vec;
}; class Person
{
public:
Person(const std::string &name_, uint8_t sex_, uint8_t age_, const std::initializer_list<int> &int_il_)
: sptr_impl(std::make_shared<PersonImpl>(name_, sex_, age_, int_il_))
{ }
//
Person(const Person &rhs)
: sptr_impl(std::make_shared<PersonImpl>(*rhs.sptr_impl))
{ }
//
Person& operator=(const Person &rhs)
{
*sptr_impl = *rhs.sptr_impl;
}
private:
std::shared_ptr<PersonImpl> sptr_impl;
};

显然若对上面代码中的两个Person对象执行Swap操作,效率很低,因为显然只需将两个对象的智能指针成员sptr_impl进行交换,而缺省版本却会将指针指向的PersonImpl对象进行三次复制。因此,需要为Person特化Swap函数,编写一个高效的版本。

编写方法:

    ①为对象提供一个public的Swap成员函数,在该函数中高效地置换两个对象的值。

    ②在定义对象类的命名空间中提供一个非成员版本的Swap函数,调用成员函数版本的Swap函数。

    ③若编写的是类而不是类模板,在成员函数版本的Swap中特化标准库版本的Swap,根据名称查找法则,会优先调用特化版本的Swap。

  代码如下:

 namespace jz
{
inline void Person::Swap(Person &rhs)
{
using stl::Swap;
Swap(sptr_impl, rhs.sptr_impl);
} //
void Swap(Person &lhs, Person &rhs)
{
lhs.Swap(rhs);
}
}

  附注:

  swap函数的用处之一就是为类和类模板提供异常安全性保障,但这种保障基于一个假设:成员函数版本的Swap函数不抛出异常(缺省版本的Swap函数使用了拷贝构造函数和拷贝赋值运算符,都有可能抛出异常)。而因为高效率地Swap函数总是基于对内置类型的操作(比如指针),且内置类型上的操作不会抛出异常,所以上面的成员函数版Swap若要保证绝对不抛出异常,应该将智能指针改为内置类型的指针。

c++下为使用pimpl方法的类编写高效的swap函数的更多相关文章

  1. 在Linux下禁用IPv6的方法小结

    在Linux下禁用IPv6的方法小结--http://www.jb51.net/LINUXjishu/335724.html 这篇文章主要介绍了在Linux下禁用IPv6的方法小结,禁用IPv6的操作 ...

  2. 在Ubuntu 12.04下采用apt-get的方法安装Qt4

    在Ubuntu 12.04下采用apt-get的方法安装Qt4 注:之前发表的一篇博客是采用编译源码的方式安装Qt4,这是很有用的方式,因为源码安装对于所有系统都是通用的,其次,在使用交叉编译器的时候 ...

  3. linux下定时执行任务方法【转】

     之前就转过一篇关于定时任务的文章,前俩天用,还的翻出来看!!!再转一次,备用,,需要的时候不用麻烦找! ----------------------------------------------- ...

  4. 在Linux下和Windows下遍历目录的方法及如何达成一致性操作

    最近因为测试目的需要遍历一个目录下面的所有文件进行操作,主要是读每个文件的内容,只要知道文件名就OK了.在Java中直接用File类就可以搞定,因为Java中使用了组合模式,使得客户端对单个文件和文件 ...

  5. PHP环境下Memcache的使用方法

    原文:PHP环境下Memcache的使用方法 原文地址:http://www.2cto.com/kf/201503/384967.html 如今互联网崛起的时代,各大网站都面临着一个大数据流问题,怎么 ...

  6. Oracle 11g RAC环境下Private IP修改方法及异常处理

    Oracle 11g RAC环境下Private IP修改方法及异常处理 Oracle 11g RAC环境下Private IP修改方法及异常处理 一. 修改方法 1. 确认所有节点CRS服务以启动 ...

  7. php读取目录及子目录下所有文件名的方法

    本文实例讲述了php读取目录及子目录下所有文件名的方法,分享给大家供大家参考.具体实现方法如下: 一般来说php中读取目录下的文件名的方式确实不少,最简单的是scandir,具体代码如下: $dir= ...

  8. Windows 和  Linux 下 禁止ping的方法

    Windows 和Linux 下 禁止ping的方法 目的: 禁止网络上的其他主机或服务器ping自己的服务器 运行环境: Windows 03.08  linux 方法: Windows 03下: ...

  9. cocos2d-x3.2下获取文件夹下所有文件名的方法

    这里提供一个函数获取文件夹下所有文件名的方法,直接上代码了. 原文地址:http://blog.csdn.net/qqmcy/article/details/36184733 // //  Visib ...

随机推荐

  1. 使用Rxjava自己创建RxBus

    https://piercezaifman.com/how-to-make-an-event-bus-with-rxjava-and-rxandroid/ https://lingyunzhu.git ...

  2. python 异常处理、进程

    目录: 异常处理 python进程 python并发之多进程 一.异常处理(try...except...) 1.程序中难免出现错误,而错误分成两种: a.语法错误: b.逻辑错误(逻辑错误) 2.异 ...

  3. JDBC连接数据库(二)

    原文地址https://blog.csdn.net/jq_ak47/article/details/55049639 Mysql for java 的JDBC 驱动库安装 1.将下载下来的5.1.40 ...

  4. python selenium webdriver方法封装(find_element_by)

    下面是对find_element_by_就行了封装,封装之后的高级方法就是getElement() 下面是具体的代码: def getElement(self, selector): "&q ...

  5. TCP三次握手和四次挥手详解

    背景描述通过上一篇中网络模型中的IP层的介绍,我们知道网络层,可以实现两个主机之间的通信.但是这并不具体,因为,真正进行通信的实体是在主机中的进程,是一个主机中的一个进程与另外一个主机中的一个进程在交 ...

  6. Element-UI中Upload上传文件前端缓存处理

    Element-UI对于文件上传组件的功能点着重于文件传递到后台处理,所以要求action为必填属性.但是如果需要读取本地文件并在前端直接处理,文件就没有必要传递到后台,比如在本地打开一个JSON文件 ...

  7. labview学习之“创建数组”函数

    “创建数组”函数 一.位置:“函数”-“编程”-“数组”-“创建数组” 其图标为: 图1 图标 二.简介: “创建数组”函数有两种模式,一种是“连接模式”,一种是“添加模式”. 如需切换两种模式,可右 ...

  8. Owin对Asp.net Web的扩展

    类库Microsoft.Owin.Host.SystemWeb 扩展HttpContext以及HttpRequest ,新增了方法GetOwinContext // // Summary: // Pr ...

  9. Python学习札记(三十) 面向对象编程 Object Oriented Program 1

    参考:OOP NOTE 1.面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. ...

  10. spark udf 初识初用

    直接上代码,详见注释 import org.apache.spark.sql.hive.HiveContext import org.apache.spark.{SparkContext, Spark ...