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 ...
随机推荐
- go-004-数据结构
在 Go 编程语言中,数据类型用于声明函数和变量. 数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存. Go 语言按类别有以下几种 ...
- C#判断用户是手机访问还是PC访问
今天在做一个wap网站时,需要限制PC用户访问.网上找了很多资料,效果都不怎么理想.其实原理就是根据HTTP_USER_AGENT判断检查用户在用什么浏览器,再根据业务做相应的逻辑处理. 代码如下: ...
- STL学习笔记--关联式容器
关联式容器依据特定的排序准则,自动为其元素排序.缺省情况下以operator<进行比较.set multiset map multimap是一种非线性的树结构,具体的说是采用一种比较高效的特殊平 ...
- Q_OBJECT宏的作用
The Q_OBJECT macro at the beginning of the class definition is necessary for all classes that define ...
- 2018 Multi-University Training Contest 10 Solution
A - Problem A.Alkane 留坑. B - Problem B. Beads 留坑. C - Problem C. Calculate 留坑. D - Problem D. Permut ...
- 20155331 2016-2017-2 《Java程序设计》第8周学习总结
20155331 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 NIO与NIO2 NIO使用频道(channel)来衔接数据节点,对数据区的标记提供了cle ...
- SQL: 拼接列
1. 因工作需要,需把两列(id,created_by)拼接成一列,结果很有意思,前5个值都是null. 2.解决方法:null加减乘除任何值都等于null,所以使用isnull函数先处理下列的值再拼 ...
- 报错org.openqa.selenium.WebDriverException: disconnected: unable to connect to renderer解决方法
做自动化时经常会遇到不兼容的问题,比如以下简单的脚本,主要是打开浏览器,然后最大化窗口,打开百度,输入内容搜索,代码如下: package com.gs.selenium; import org.op ...
- Python笔记 #10# Histograms
1.Build a histogram In [1]: help(plt.hist) Help on function hist in module matplotlib.pyplot: hist(x ...
- linux中readl()和writel()函数---用于读写寄存器
writel() 往内存映射的 I/O 空间上写数据,wirtel() I/O 上写入 32 位数据 (4字节). 原型: #include <asm/io.h> void writel ...