侧边栏壁纸
博主头像
如此肤浅

但行好事,莫问前程!

  • 累计撰写 52 篇文章
  • 累计创建 6 个标签
  • 累计收到 6 条评论

目 录CONTENT

文章目录

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

如此肤浅
2022-06-02 / 0 评论 / 0 点赞 / 19 阅读 / 1,629 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-06-03,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

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

swap 原本只是 STL 的一部分,但后来成为异常安全性编程(见条款29)的重要一部分,以及用来处理自我赋值可能性(见条款11)的一个常见机制。

swap 的功能是将两个对象的值赋值给彼此。缺省情况下 swap 动作可由标准库提供的swap 算法完成。swap 的典型实现如下:

namespace std {
	template<typename T> 
    void swap(T& a, T& b)
    {
    	T temp(a);
        a = b;
        b = temp;
    }
}

只要类型 T 支持 copying(通过 copy 构造函数和 copy assignment 操作符完成),缺省的 swap 实现代码就会帮你置换类型为 T 的对象,你不需要为此另外再做任何工作。

swap 函数存在的问题

在“pimpl”手法中(pimpl 是“pointer to implementation”的缩写,见条款31),设计一个类 Widget:

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

一旦要置换两个 Widget 对象,我们唯一需要做的就是置换其 pImpl 指针,但缺省的 swap 算法不知道这一点。它不止复制3个 Widgets,还复制3个 WidgetImpl 对象,效率很低下!

正确的做法

class Widget { // 与前面相同,唯一区别是增加swap函数
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); // 若要置换Widgets,调用其swap成员函数
    }
}

上述代码中,“template<>”表示它是 std::swap 的一个全特化版本,函数名称之后的“< Widget>”表示这一特化版本是针对“T 是 Widget”而设计的。换句话说当一般性的 swap template 施行于 widgets 身上便会启用这个版本。通常我们不被允许改变 std 命名空间内的任何东西,但被允许为标准 templates(如 swap)制造特化版本,使它专属于我们自己的 classes(例如widget)。上述代码正是如此。

然而假设 Widget 和 WidgetImpl 都是class templates 而非 classes 时,情况有些特殊
没看懂,后面再回来看

0

评论区