[Effective C++ --025]考虑写出一个不抛异常的swap函数
引言
在我的上一篇博客中,讲述了swap函数。
原本swap只是STL的一部分,而后成为异常安全性编程的脊柱,以及用来处理自我赋值可能性。
一、swap函数
标准库的swap函数如下:
namespace std {
template<typename T>
void swap(T &a, T& b)
{
T temp(a);
a = b;
b = temp;
}
}
只要类型T支持拷贝(通过拷贝构造函数和拷贝赋值操作符完成),那么这个版本的swap函数就会帮你置换类型为T的对象。
二、Pimpl情境下的swap函数
假设我们有如下的类。
class WidgetImpl {
public:
...
private:
int a,b,c; // 可能有许多数据
std::vector<double> v; // 意味复制时间很长
....
} class Widget {
public:
Widget(const Widget& rhs);
Widget& operator = (const Widget& rhs)
{
.....
*pImpl = *(rhs.pImpl);
}
private:
WidgetImpl* pImpl;
};
一旦要置换两个Widget对象,我们唯一需要做的就是置换其pImpl指针,但是一种的swap函数不知道这一点,它会复制三个Widget和三个WidgetImpl,效率非常低下!
所以我们希望的效果是:只交换pImpl指针!
因此我们可以设计出这个思路:
namespace std {
template<> // 表示它是std::swap的一个特化版本
void swap<Widget>(Widget &a, Widget& b)
{
swap(a.pImpl, b.pImpl);
}
}
上述代码当然通不过编译,因为pImpl是私有成员。或许你说我们可以用friend函数来解决这一问题,可是这不大符合预期!
那我们再包装一下:
class Widget {
public:
...
void swap(Widget& other)
{
using std::swap;
swap(pImpl, other.pImpl); // 若置换Widgets就置换其pImpl指针
}
....
} namespace std {
template<> // 表示它是std::swap的一个特化版本
void swap<Widget>(Widget& a, Widget& b)
{
a.swap(b);
}
}
这样不仅通过编译,还与STL容器具有一致性,因为所有的STL容器也都提供有public swap成员函数和std::swap特化版本。
但需要注意的是:C++只允许对class templates偏特化,在function template上特化是行不通的。如下面代码是编译不过的。
namespace std {
template<typename T>
void swap<Widget<T>>(Widget<T>& a,
Widget<T>& b)
{
swap(a.pImpl, b.pImpl);
}
}
三、function template偏特化
那么,如果我们想在function template上特化,应该怎么做呢?答案是添加一个重载版本!
如下:
namespace std {
template<typename T>
void swap(Widget<T>& a, // 注意这里没有“<Widget<T>>”
Widget<T>& b)
{
swap(a.pImpl, b.pImpl);
}
}
同时,为了其他人调用swap时能取得我们提供的较高版本的template特定版本,我们可以声明一个non-member函数!
namespace Widget {
template<typename T>
class Widget{....} template<typename T>
void swap(Widget<T>& a, // 注意这里没有“<Widget<T>>”
Widget<T>& b)
{
swap(a.pImpl, b.pImpl);
}
}
◆总结
1.当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异常。
2.如果你提供一个member swap,也该提供一个non-member swap用来调用前者。对于classes,也请特化std::swap。
3.调用swap时应针对std::swap使用using声明式,然后调用swap并且不带任何“命名空间资格修饰”。
4.为“用户定义类型”进行std template全特化是好的,但千万不要尝试在std内加入某些对std而言全新的东西
[Effective C++ --025]考虑写出一个不抛异常的swap函数的更多相关文章
- Effective C++:条款25:考虑写出一个不抛异常的swap函数
(一) 缺省情况下swap动作可由标准程序库提供的swap算法完毕: namespace std { template<typename T> void swap(T& a, T& ...
- 《Effective C++》item25:考虑写出一个不抛异常的swap函数
std::swap()是个很有用的函数,它可以用来交换两个变量的值,包括用户自定义的类型,只要类型支持copying操作,尤其是在STL中使用的很多,例如: int main(int argc, _T ...
- Effective C++ Item 25 考虑写出一个不抛异常的swap函数
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛 ...
- EC读书笔记系列之13:条款25 考虑写出一个不抛异常的swap函数
记住: ★当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定其不抛出异常 ★若你提供一个member swap,也该提供一个non-member swap来调用前者.对于cla ...
- Effective C++ -----条款25:考虑写出一个不抛异常的swap函数
当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异常. 如果你提供一个member swap,也该提供一个non-member swap用来调用前者.对于cla ...
- 【25】考虑写出一个不抛异常的swap函数
1.swap交换对象值,std提供了实现方法模版的实现,它的实现是交换对象值. namespace std { template<typename T> void swap(T& ...
- 考虑实现一个不抛异常的swap
Effective C++:参考自harttle land 类的swap实现与STL容器是一致的:提供swap成员函数, 并特化std::swap来调用那个成员函数. class Widget { p ...
- 输入一个数字n 如果n为偶数则除以2,若为奇数则加1或者减1,直到n为1,求最少次数 写出一个函数
题目: 输入一个数字n 如果n为偶数则除以2,若为奇数则加1或者减1,直到n为1,求最少次数 写出一个函数 首先,这道题肯定可以用动态规划来解, n为整数时,n的解为 n/2 的解加1 n为奇数时 ...
- java————数组 简单写出一个管理系统
数组的特点 1, 数组是一块连续的空间,下标描述空间的位置. 2, 下标从0开始,最大下标为数组长度—1.(*.length-1) 3, 数组元素都是变量.(就是每个下标对应的内容).变量的类型 ...
随机推荐
- 【转】@Override must override a superclass method 问题解决
原文网址:http://www.blogjava.net/anchor110/articles/339352.html 如果在使用Eclipse开发Java项目时,在使用 @Override 出现以下 ...
- 【原】cocos2d-x开发笔记:多点触控
在项目开发中,我们做的大地图,一个手指头按下滑动可以拖动大地图,两个手指头按下张开或者闭合,可以放大和缩小地图 在实现这个功能的时候,需要使用到cocos2d-x的多点触控功能. 多点触控事件,并不是 ...
- 问题与解答 [Questions & Answers]
您可以通过发表评论的方式提问题, 我如果有时间就会思考, 并给出答案的链接. 如果您学过Latex, 发表评论的时候请直接输入Latex公式; 反之, 请直接上传图片 (扫描.拍照.mathtype ...
- SSL 通信原理及Tomcat SSL 配置
SSL 通信原理及Tomcat SSL 双向配置 目录1 参考资料 .................................................................. ...
- 点亮一个led
1:RS232电平:计算机串口 高电平为-12v,低电平为+12v,所以计算机与单片机进行通信的时候需要加电平转换芯片max232(高电平为-9到-12,低电平为+3到+12之间的. max232通常 ...
- 字符串旋转(str.find()---KMP)
此题旋转带有技巧性,问题转化为常见的问题,熟练STL可以直接用str.find()函数,其是主要想用KMP算法实现字符串的查找算法... //如果对于一个字符串A,将A的前面任意一部分挪到后边去形成的 ...
- C++多线程框架-----Mutex互斥和Sem信号量
互斥和信号量是多线程编程的两个基础,其原理就不详细说了,大家去看看操作系统的书或者网上查查吧. 对于互斥的实现,无论什么操作系统都离不开三个步骤 1.初始化互斥锁 2.锁操作 3.解锁操 ...
- 【Hadoop学习】Apache Hadoop项目简介
正在撰写,稍后来访……
- iso定制封装
http://xiaoli110.blog.51cto.com/1724/1617541
- 沈晓军 / LarvaFrame - 代码托管 - 开源中国社区
沈晓军 / LarvaFrame - 代码托管 - 开源中国社区 统计