c++下为使用pimpl方法的类编写高效的swap函数
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函数的更多相关文章
- 在Linux下禁用IPv6的方法小结
在Linux下禁用IPv6的方法小结--http://www.jb51.net/LINUXjishu/335724.html 这篇文章主要介绍了在Linux下禁用IPv6的方法小结,禁用IPv6的操作 ...
- 在Ubuntu 12.04下采用apt-get的方法安装Qt4
在Ubuntu 12.04下采用apt-get的方法安装Qt4 注:之前发表的一篇博客是采用编译源码的方式安装Qt4,这是很有用的方式,因为源码安装对于所有系统都是通用的,其次,在使用交叉编译器的时候 ...
- linux下定时执行任务方法【转】
之前就转过一篇关于定时任务的文章,前俩天用,还的翻出来看!!!再转一次,备用,,需要的时候不用麻烦找! ----------------------------------------------- ...
- 在Linux下和Windows下遍历目录的方法及如何达成一致性操作
最近因为测试目的需要遍历一个目录下面的所有文件进行操作,主要是读每个文件的内容,只要知道文件名就OK了.在Java中直接用File类就可以搞定,因为Java中使用了组合模式,使得客户端对单个文件和文件 ...
- PHP环境下Memcache的使用方法
原文:PHP环境下Memcache的使用方法 原文地址:http://www.2cto.com/kf/201503/384967.html 如今互联网崛起的时代,各大网站都面临着一个大数据流问题,怎么 ...
- Oracle 11g RAC环境下Private IP修改方法及异常处理
Oracle 11g RAC环境下Private IP修改方法及异常处理 Oracle 11g RAC环境下Private IP修改方法及异常处理 一. 修改方法 1. 确认所有节点CRS服务以启动 ...
- php读取目录及子目录下所有文件名的方法
本文实例讲述了php读取目录及子目录下所有文件名的方法,分享给大家供大家参考.具体实现方法如下: 一般来说php中读取目录下的文件名的方式确实不少,最简单的是scandir,具体代码如下: $dir= ...
- Windows 和 Linux 下 禁止ping的方法
Windows 和Linux 下 禁止ping的方法 目的: 禁止网络上的其他主机或服务器ping自己的服务器 运行环境: Windows 03.08 linux 方法: Windows 03下: ...
- cocos2d-x3.2下获取文件夹下所有文件名的方法
这里提供一个函数获取文件夹下所有文件名的方法,直接上代码了. 原文地址:http://blog.csdn.net/qqmcy/article/details/36184733 // // Visib ...
随机推荐
- 配置Tomcat直接显示目录结构和文件列表
Tomcat是直接显示目录结构和文件列表,只是在配置里面给关闭了. 关键在这里:\conf\web.xml 这个文件有一段配置直接控制Tomcat是允许显示目录结构和文件列表. <servlet ...
- docker——Etcd高可用键值对数据库
一.简介 Etcd按照官方介绍: Etcd is a distributed, consistent key-value store for shared configuration and serv ...
- Redis在Linux下的安装与配置
Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. Redis是 NoSQL技术阵营中的一员. 说到NoSQL, ...
- Ubuntu vim java 自动补全javacomeplete2
一 安装vundle $ git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim 默认安装在/.v ...
- struts2.1.8 spring2.5.6 hibernate3.3G 依赖jar包
----struts2.1.8---- struts2-core-2.1.8.1.jar struts2核心包 struts2-json-plugin-"} struts2-spring-p ...
- 使用索贝尔(Sobel)进行梯度运算时的数学意义和代码实现研究
对于做图像处理的工程师来说,Sobel非常熟悉且常用.但是当我们需要使用Sobel进行梯度运算,且希望得到“数学结果”(作为下一步运算的基础)而不是“图片效果”的时候,就必须深入了解Sobel的知识原 ...
- asp.net调用opencv类库,实现图像处理显示
asp.net调用opencv类库,实现图像处理显示 原理上来说,通过dll的调用,无论是asp.net还是winform都可以调用opencv及其类库.但是在实现的过程还是有许 ...
- 20145204 《Java程序设计》第1周学习总结
20145204 <Java程序设计>第1周学习总结 教材学习内容总结 本周经过不断的钻研课本,及看一些老师的视频,我对Java有了一个全新的认知.是的,Java和C都是一种语言,但是Ja ...
- 20145315 《Java程序设计》第五周学习总结
20145315 <Java程序设计>第五周学习总结 教材学习内容总结 第八章 8.1语法与继承架构 8.1.1使用try,catch 所有的错误都会被打包为对象,使用try,catch可 ...
- Nature 为引,一文看懂个体化肿瘤疫苗前世今生
进入2017年,当红辣子鸡PD-1疗法,一路横扫多个适应症.而CAR-T治疗的“小车”在获得FDA专委会推荐后也已经走上高速路,成为免疫治疗又一里程碑事件.PD-1.CAR-T之后,下一个免疫治疗产品 ...