您的位置:首页 > 编程语言 > C语言/C++

【Effective C++读书笔记】篇十(条款25)

2016-07-28 21:07 411 查看
条款25:考虑写出一个不抛异常的 swap 函数                              

 

swap 函数是一个有趣的函数。原本它只是 STL 的一部分,而后成为异常安全性编程的脊柱,以及用来处理自我赋值可能性的一个常性机制。由于 swap 如此有用,适当的实现很重要。然而在非凡的重要性之外,它也带来了非凡的复杂度。本条款探讨这些复杂度及因应之道。

1、当 swap 的缺省实现码对你的 class 或 class template 提供可接受的效率,那么你不需要额外做任何事情。

2、其次,如果 swap 缺省实现版本的效率不足(那几乎总是意味你的 class 或 template 使用了某种 pimpl 手法),试着做一下事情:

1)提供一个 public swap 成员函数,让它高效地置换你的类型的两个对象值。

2)在你的 class 或 template 所在的命名空间内提供一个 non-member swap ,并令它调用 上述 swap  成员函数。

3)如果你正在编写一个 class (而非 class template),为你的 class 特化 std::swap。并令它调用你的 class 成员函数。

3、最后,如果你调用 swap ,请确定包含一个 using 声明式,以便让 std::swap 在你的函数内曝光可见,然后不加任何 namespace 修饰符,赤裸裸地调用 swap。

唯一还未明确的劝告:成员版 swap 绝不可抛出异常。那是因为 swap 的一个最好的应用是帮助 classes (和 class template)提供强烈的异常安全性(exception-safety)保障。条款29对此主题提供了所有细节,但此技术基于一个假设:成员版 swap 绝不抛出异常。这一约束只施行于成员版!不可实施于非成员版,因为 swap
缺省的版本是以 copy 构造函数和 copy assignment 操作符为基础,而一般情况下两者都允许抛出异常。因此当你写下一个自定义版本的 swap ,往往提供的不只是高效置换对象的办法,而且不抛出异常。一般而言这两个特性是连在一起的,因为高效率的 swap 几乎总是基于对内置类型的操作(例如 pimpl 手法的底层指针),而内置类型上的操作绝对不会抛出异常。

首先举个 std::swap 特化的例子:

g.h

#ifndef _G_H_
#define _G_H_

class point
{
public:
point(int size):size(size)
{
pi = new int[size];
cout << "point()" << this << ":" << pi << endl;
}
void swap(point &rp)
{
cout << "point::swap" << endl;
size_t tmp = rp.size;
int *ptmp = rp.pi;
rp.pi = pi;
rp.size = size;
pi = ptmp;
size = tmp;
}
~point()
{
cout << "~point()" << this << ":" << pi << endl;
delete[] pi;
}
private:
int *pi;
size_t size;
};

namespace std
{
template<>
void swap(point &rp1, point &rp2)
{
cout << "std::swap" << endl;
rp1.swap(rp2);
}
}
#endif
g.cpp

#include <iostream>
using namespace std;

#include "g.h"

int main()
{
point p1(2);
point p2(4);
swap(p1, p2);
return 0;
}

输出如下:
point()0xbff7f290:0x8d86008
point()0xbff7f298:0x8d86018
std::swap
point::swap
~point()0xbff7f298:0x8d86008
~point()0xbff7f290:0x8d86018

发现 main 函数确实是先调用了全特化的 std::swap,然后再调用了 member swap。

对于 class template 类似,但由于 std 空间不支持偏特化,所以不能使用 std::swap,只能在 class template 的命名空间或全局空间里新加一个 non-member swap 函数以备调用。代码如下:

g.h

#ifndef _G_H_
#define _G_H_

template<typename T>
class point
{
public:
point(int size):size(size)
{
pi = new T[size];
cout << "point()" << this << ":" << pi << endl;
}
void swap(point<T> &rp)
{
cout << "point::swap" << endl;
size_t tmp = rp.size;
T *ptmp = rp.pi;
rp.pi = pi;
rp.size = size;
pi = ptmp;
size = tmp;
}
~point()
{
cout << "~point()" << this << ":" << pi << endl;
delete[] pi;
}
private:
T *pi;
size_t size;
};

template<typename T>
void swap(point<T> &rp1, point<T> &rp2)
{
cout << "std::swap" << endl;
rp1.swap(rp2);
}
#endif

g.cpp
#include <iostream>
using namespace std;

#include "g.h"

int main()
{
point<int> p1(2);
point<int> p2(4);
swap(p1, p2);
return 0;
}

得到的结果:
point()0xbfd5f340:0x839c008
point()0xbfd5f348:0x839c018
std::swap
point::swap
~point()0xbfd5f348:0x839c008
~point()0xbfd5f340:0x839c018


这里为了简单,我的 T 使用了 int 型,而未使用自定义的某个类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: