[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, 数组元素都是变量.(就是每个下标对应的内容).变量的类型 ...
随机推荐
- Java [leetcode 21]Merge Two Sorted Lists
题目描述: Merge two sorted linked lists and return it as a new list. The new list should be made by spli ...
- Entity Framework 增删改查和事务操作
1.增加对象 DbEntity db = new DbEntity(); //创建对象实体,注意,这里需要对所有属性进行赋值(除了自动增长主键外),如果不赋值,则会数据库中会被设置为NULL(注意是否 ...
- Android中Bitmap和Drawable,等相关内容
一.相关概念 1.Drawable就是一个可画的对象,其可能是一张位图(BitmapDrawable),也可能是一个图形(ShapeDrawable),还有可能是一个图层(LayerDrawable) ...
- VS2010 Chromium编译
推荐使用Windows 7及以后系统,最少8G内存,预留出50G磁盘空间 搭建Visual Studio 2010开发环境 1.安装Visual Studio 2010专业版或者旗舰版 2.安装VS2 ...
- C#操作Json(转)
原文:http://wenku.baidu.com/link?url=3dlqKdF26ZdQIAcX9jvP2ZYEtl3J0sKOV8XuHQI0Rz4SjB9S46nqmGiMXUVQa_1Pm ...
- ubuntu安装和卸载软件命令
ubuntu安装和卸载软件命令 Ubuntu软件安装与删除相关命令 安装软件 命令: apt-get install softname1 softname2 softname3…… 卸载软件 命令: ...
- JDK1.5新特性(七)……Annotations
概述 Annotations (Metadata) - This language feature lets you avoid writing boilerplate code under many ...
- ZOJ3469 Food Delivery 区间DP
题意:有一家快餐店送外卖,现在同时有n个家庭打进电话订购,送货员得以V-1的速度一家一家的运送,但是每一个家庭都有一个不开心的值,每分钟都会增加一倍,值达到一定程度,该家庭将不会再订购外卖了,现在为了 ...
- uva 11468 Substring
题意:给你 k 个模板串,然后给你一些字符的出现概率,然后给你一个长度 l ,问你这些字符组成的长度为 l 的字符串不包含任何一个模板串的概率. 思路:AC自动机+概论DP 首先用K个模板构造好AC自 ...
- 2014上海网络赛 HDU 5053 the Sum of Cube
水 #include <stdio.h> #include <stdlib.h> #include<math.h> #include<iostream> ...