IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 条款 25 :考虑写出一个不抛出异常的swap函数 -> 正文阅读

[C++知识库]条款 25 :考虑写出一个不抛出异常的swap函数

条款 25 :考虑写出一个不抛出异常的swap函数

Consider support for a non-throwing swap.

  1. 所谓swap(置换)两对象值,意思是将两对象的值彼此赋予对方。标准库缺省swap函数典型实现如下:
namespace std{
	template<typename T>
	void swap(T& a,T& b){
	T temp(a);
	a=b;
	b=temp;
	}
}

在上述代码中只要类型T支持copying,缺省的swap实现代码会自动完成对象的置换。观察上述代码,其涉及了三个对象的复制,但是细想,对于一些类型这些复制是没有必要的。若是非要这么写,无疑是降低了速度。其中最主要的形式就是”以指针指向一个对象,内含真正数据“即所谓的"pimpl手法"(pointer to implementation)我们来看下列例子:

class WidgetImpl{//针对Widget数据而设计的class
public://细节不重要
	...
private:
	int a,b,c;
	std::vector<double> v;//可能有很多数据,意味着复制时间长
	...
};
class Widget{//这个class使用pimpl手法
public:
	Widget(const Widget& rhs);
	Widget& operator=(const Widget& rhs){
		...//复制Widget时,令其复制其WidgetImpl对象
		*pImpl=*(rhs.pIml);
		...
	}
	...
private:
	WidgetImpl* pImpl;//指针,所值对象内含Widget数据
};

使用这个类我们一旦要置换两个Widget对象值,我们唯一需要做的就是置换其pImpl指针,但是问题是缺省的swap函数是不知道这一点的。明确告诉swap的具体实践是将std::swap对Widget特化。下面是基本思想:

namespace std{//这是针对std::swap的T是Widget的特化版本
	template<>//改代码目前还不能通过编译
	void swap<Widget>(Widget& a,Widget& b){
		swap(a.pImpl,b.pImpl);//置换时只置换指针
	}
}

上述函数一开始的template<>表示他是std::swap的一个全特化版本,函数之后的< Widget >表示这个特化版本是针对T是Widget而设计的。换一句话说就是:当一般性的swap用在Widget身上时就启用这个版本。通常情况下我们不能够(不被允许)更改std内的任何的任何内容,但是可以被允许为标准template制造特化版本。
我们说过上述代码还无法通过编译,原因是pImpl只private,而swap却妄想直接利用。解决之道就是,令特化的swap成为其friend.这里的声明方式与以往不太相同,我们的做法是:令Widget声明一个名为swap的public成员函数来做真正的置换工作,然后将std::swap特化,令他调用该函数成员:

class Widget{
public:
	...
	void swap(Widget& other){
		using std::swap;//这个声明是有必要的,说明该域内的swap为std::swap
		swap(pImpl,other.pImpl);//若要置换,就置换指针
	}
	...
};
namespace std{//修订后的特化版本
	template<>
	void swap<Widget>(Widget& a,Widget& b){
		a.swap(b);//若要置换,调用其swap成员函数
	}
}

该做法不仅能通过编译,还与STL行为一致了。(具体不细说了)
然而当Widget和WidgetImpl都是calsses template而不是calsses时,我们也可以对WidgetImpl内的数据类型加以参数化:

template<typename T>
class WidgetImpl{...};
template<typename T>
class Widget{...};

想想上述情况我们的特化swap怎么写,看看下述代码:

namespace std{
	template<typename>
	void swap<Widget<T>>(Widget<T>& a,Widget<T>& b){//不合法
		a.swap(b);//若要置换,调用其swap成员函数
	}
}

这看起来是合乎情理的,但是不合法。原因是:我们企图偏特化一份function template,但是C++只允许对calsses template偏特化,在function template上偏特化是行不通的。
当你打算偏特化一个函数模板,常用方法是为其添加一个重载版本,看下述代码:

namespace std{
	template<typename>
	void swap(Widget<T>& a,Widget<T>& b){//这也不合法
		a.swap(b);//若要置换,调用其swap成员函数
	}
}

一般而言重载函数模板是没有问题的,但是std标准由C++标准成员会给出,他不允许添加你自己的function template版本。 所以上述代码依旧行不通。
为了解决这个问题,我们的做法是:我们声明一个non-member swap让他调用member swap,但这个non-member swap不再是std::swap的特化版本或重载版本。来看下列代码:

namespace WidgeStuff{
	...
	template<typename T>
	class Widget{...};
	...
	void swap(Widget<T>& a,Widget<T>& b){//这里并不属于std了
		a.swap(b);//若要置换,调用其swap成员函数
	}

那么现在调用置换时,就会调用该空间的swap而不会影响std。

请记住

1. 当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异常。
2. 如果你提供一个member swap,也应该提供一个non-member swap来调用前者。对于calsses(而非template),也请特化std::swap.
3. 调用swap时应该针对std::swap使用using 声明,然后调用swap并且不带任何”命名空间修饰资格“。
4. 为用户定义类型进行std template全特化是好的,但千万不要尝试在std内加入某些对std而言全新的东西。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-06 12:00:37  更:2021-10-06 12:04:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:23:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码