Effective C++笔记_条款25考虑写出一个不抛出异常的swap函数

  1 // lib中的swap
  2 namespace std {
  3     template<typename T> 
  4     void swap (T& a, T& b)
  5     {
  6         T temp(a);
  7         a = b;
  8         b = temp;
  9     }
 10 }
 11 
 12 // 缺点:需要赋值大量的数据,但是有的时候并不要复制如此多的内容
 13 class WidgetImpl {
 14 public:
 15     //...
 16 private:
 17     int a, b, c;
 18     std::vector<double> v;     // 可能有很多数据,以为复制时间很长
 19     //...
 20 };
 21 
 22 class Widget {
 23 public:
 24     Widget(const Widget& rhs);
 25     Widget& operator= (const Widget& rhs) 
 26     {
 27         //...
 28         *pImpl = *(rhs.pImpl);
 29         //....
 30     }
 31 private:
 32     WidgetImpl *pImpl;
 33 };
 34 
 35 // 对于上面这个实例来说,只需要交换指针就好了,没有必要进行全部的值的交换。
 36 // 为了解决这个问题,需要将std::swap针对Widget特化。说白一点就是专门为Widget
 37 // 设计一个swap函数
 38 // 解决方案
 39 class Widget {
 40 public:
 41     Widget(const Widget& rhs);
 42     Widget& operator= (const Widget& rhs) 
 43     {
 44         //...
 45         *pImpl = *(rhs.pImpl);
 46         //....
 47     }
 48 
 49     // 注意哟,重点到了.实现真正的置换工作
 50     void swap(Widget& other)
 51     {
 52         using std::swap;
 53         swap(pImpl, other.pImpl);
 54     }
 55 
 56 private:
 57     WidgetImpl *pImpl;
 58 };
 59 
 60 // 注意哟,下面是针对Widget类的特化swap,它调用Widget的swap函数
 61 namespace std {
 62     template<>       // 1.全特化
 63     void swap<Widget>(Widget& a, Widget& b)   // 2.表明这个swap函数专门给Widget特化的
 64     {
 65         a.swap(b);
 66     }
 67 }
 68 
 69 // 面对class templates 又如何呢
 70 template<typename T>
 71 class WidgetImpl {
 72     //...
 73 };
 74 
 75 template<typename T> 
 76 class Widget {
 77     //...
 78 };
 79 
 80 /*
 81  错误哟:C++只允许对class templates 偏特化,在function templates偏特化是行不通的
 82  客户可以全特化std内的templates(template<>),但是不可以添加新的templates(或classes
 83  或functions或其他任何东西)到std里头。
 84 */
 85 namespace std {
 86     template<typename T>
 87     void swap< Widget<T> > (Widget<T>& a, Widget<T>& b)
 88     {
 89         a.swap(b);     
 90     }
 91 };
 92 
 93 // ----- solution  -----
 94 namespace WidgetStuff {
 95     class WidgetImpl {
 96     public:
 97         //...
 98     private:
 99         int a, b, c;
100         std::vector<double> v;     // 可能有很多数据,以为复制时间很长
101         //...
102     };
103 
104     class Widget {
105     public:
106         Widget(const Widget& rhs);
107         Widget& operator= (const Widget& rhs) 
108         {
109             //...
110             *pImpl = *(rhs.pImpl);
111             //....
112         }
113 
114         // 注意哟,重点到了.实现真正的置换工作
115         void swap(Widget& other)
116         {
117             using std::swap;
118             swap(pImpl, other.pImpl);
119         }
120 
121     private:
122         WidgetImpl *pImpl;
123     };
124 
125     template<typename T>
126     void swap(Widget<T>& a, Widget<T>& b)
127     {
128         a.swap(b);                   // 调用Widget中的swap函数
129     }
130 }

总结: 

        当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异常。

        如果你提供一个member swap,也该提供一个non-member swap用来调用前者。对于classes(而非templates),也请特化std::swap。

        调用swap时应该针对std::swap使用using声明式,然后调用swap并且不带任何“命名空间资格修饰”。

        为“用户定义类型”进行std template 全特化是好的,但千万不要尝试在std内加入某些std而言全新的东西。

=======================================================================
所有内容都是用BSD条款。 Copyright (C) by CloudFeng.
原文地址:https://www.cnblogs.com/cloudfeng/p/4354552.html