標籤:
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而言全新的東西。
Effective C++筆記_條款25考慮寫出一個不拋出異常的swap函數