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 ...
随机推荐
- Underscore.js (1.7.0)-集合(Collections)(25)
稽核函数(数组或对象) each_.each(list, iteratee, [context]) 别名: forEach 遍历list中的所有元素,按顺序用遍历输出每个元素.如果传递了context ...
- EOS token 代币兑换的资料
eos token 兑换价格预估查询: https://eosscan.io/ https://steemit.com/eos/@sandwich/how-to-check-which-eos-p ...
- MySQL多个相同结构的表查询并把结果合并放在一起的语句(union all)
union all select *,'1' as category from table1001 where price > 10 union all select *,'2' as cate ...
- thinkphp5使用PHPMailler发送邮件
http://www.dawnfly.cn/article-1-350.html 想要了解thinkphp3.2版本发送邮件的,请点击此链接:http://www.dawnfly.cn/article ...
- [css]网站骨架布局作业
实现效果图: 代码实现 第一次写的时候不知道如何下手, 后来摸清规律了,由大到小. 由全局到局部 第一次还遇到区块命名问题, 和哪个该怎么划分问题 第一次还遇到由于划分不规整,所以有些代码没达到预期的 ...
- Python---1. 基础数据类型
转载: Py西游攻关之基础数据类型
- python3 应用 nose_parameterized 实现unittest 参数化
一.读取变量的值,实现unittest 参数化 import nose_parameterized,unittest def calc(a:int,b:int): return a+b case_da ...
- char *strstr(const char *str1, const char *str2);
[FROM MSDN && 百科] 原型:char *strstr(const char *str1, const char *str2); #include<string.h& ...
- zwPython,字王集成式python开发平台,比pythonXY更强大、更方便。
zwPython,字王集成式python开发平台,比pythonXY更强大.更方便. 更强大,内置opencv.cuda/opencl.NLTK自然语言.pygame游戏设计等多个重量级模块库. 更方 ...
- CentOS7 忘了root密码怎么办
今天打开很久没开机的另2台虚拟机,发现不记得root密码了. 于是参考了google搜索到的第一个答案,https://www.unixmen.com/reset-root-password-cent ...