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而言全新的东西。