美文网首页
实现一个不抛异常的swap函数

实现一个不抛异常的swap函数

作者: wayyyy | 来源:发表于2018-08-31 01:12 被阅读0次
template<typename T>
void swap(T& a, T& b)
{
    T temp(a);  // 拷贝构造
    a = b;      // 拷贝赋值运算符
    b = temp;   // 拷贝赋值运算符
}

一个基本的swap函数大概如上所述,但是对某些类型而言。典型比如:pimpl手法(pointer to implementation),这些复制没有必要。

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对象。

我们希望能够告诉std::swap,当Widgets被置换时真正该做的是置换其内部的pImpl指针,确切的做法就是:将std::swap针对Widget特化。

namespace std {
    template<>
    void swap<Widget>(Widget& a, Widget& b)
    {
        swap(a.pImpl, b.pImpl);
    }
}

通常我们不被允许改变std命名空间内的任何东西,但可以为标准的template制造特化版本。
虽然上面的代码看起来达到我们的目的,但实际上这个函数无法通过编译,因为它企图访问 a 和 b 内的Impl指针,而那是private的。
但我们可以在内部实现一个swappublic成员函数做真正的置换工作,然后将std::swap特化,令它调用成员函数:

class Widget
{
    public:
        ...
        void swap(Widget& other)
        {
            using std::swap;
            swap(pImpl, other.pImpl);
        }
    ...
};

namespace std
{
    template<>
    void swap<Widget>(Widget& a, Widget &b)
    {
        a.swap(b);
    }
}

这种做法不仅能通过编译,还与STL容器有一致性,因为所有的STL容器也都提供有public swap成员函数和std::swap特化版本。

  • using std::swap

  • 不抛异常
    成员版swap最好实现成不要抛异常,因为swap的一个最好应用是帮助class提供异常安全保障。此技术基于一个假设:成员版的swap绝不抛异常。但这一约束只约束于成员版,不可施行于非成员版,因为swap缺省版本是以拷贝构造和拷贝赋值操作符为基础,而一般情况下两者都允许抛异常。

总结
  • 如果swap的缺省实现对你的classclass template提供可接受的效率。那么不需要做额外的操作。
    如果swap的缺省实现版本效率不足,试着做下面的事情:
    • 提供一个public swap成员函数,让它高效的置换你的类型的两个对象值,并且这个swap函数绝不能抛出异常。
    • 在你的classtemplate所在的命名空间内提供一个non-member swap,并令它调用上述swap成员函数。
    • 如果你在编写一个class而非class template,为你的class特化std::swap

相关文章

  • 实现一个不抛异常的swap函数

    一个基本的swap函数大概如上所述,但是对某些类型而言。典型比如:pimpl手法(pointer to imple...

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

    《Effective C++ 中文版 第三版》读书笔记 ** 条款 25:考虑写出一个不抛异常的 swap 函数 ...

  • C++11新特性

    宏 函数名 只包含一次头文件 变长参数 noexcept 异常 声明函数不会抛异常 声明函数可以抛异常 例如析够函...

  • Effective C++ Term 26 实现一个不抛出异常的

    其实这条 Term 的重点不在于抛出异常,而在于怎么实现一个高效的swap,不抛出异常的要求是相对比较好保证的 标...

  • pyspider捕获404异常,包括所有的非200状态码

    如果请求的状态码不是200,那么肯定会抛异常的 要实现的目的是,禁止框架抛出异常 那么需要在回调函数上加上一个装饰...

  • Guava学习(二)

    早上上课 笔记: Exception 构造函数需要有一个Trowable参数. 抛异常的时候要改变异常类型参数应加...

  • ByteBuddy(六)—使用@OnMethodExit Adv

    Advice代码可以拦截从函数代码抛出的异常。 Advice代码还可以将异常抑制为空,或者抛出一个新的异常来替换抛...

  • 今日python学习

    今天主要学习了两个函数:swap(替换函数),changeA(修改函数) 1:swap函数: 2:changeA函...

  • C++11泛型-函数模板

    一、为什么要有函数模板 在泛型编程出现前,我们要实现一个swap函数得这样写: 但这个函数只支持int型的变量交换...

  • 冒泡

    首先来声明个swap模板函数 //定义模板函数 template void swap(T...

网友评论

      本文标题:实现一个不抛异常的swap函数

      本文链接:https://www.haomeiwen.com/subject/mcmlwftx.html