Item 25 不應丟擲異常的swap

2021-08-25 20:18:20 字數 1279 閱讀 1194

通用的swap可以在stl裡找到:

namespace std }

有很多類使用pimpl來分離實現與介面,對它們的swap要慎重。

class widgetimpl ; class widget ... private: widgetimpl *pimpl; };

其實,swap只要交換二者的指標即可,不用拷貝裡面的資料:

void widget::swap(widget& other) namespace std }

stl裡的容器都是這樣實現swap的。

現在假設widget和widgetimpl都是模板類,即:

templateclass widget ; templateclass widgetimpl ;

那麼,如何實現swap呢?下面這樣的思路可以嗎:

namespace std }

實際上,對模板函式的定義進行「partial specialization」在c++中是無效的。如果編譯通過,說明編譯器有問題。

不過,對模板類,可以進行「partial specialization」。

那麼,過載swap可以解決問題嗎:

namespace std }

但是,std這個名字空間,是不適合用上面的方法解決問題的。這屬於對std空間增加了新的模板類。

而std空間的內容,只有c++委員會才有權決定。

可能上面的**在一些編譯器上可以正常執行,比如vc,但實際上屬於「未定義行為」!

需要稍稍改一下:

namespace widgetstuff ; // member function ... templatevoid swap(widget& a, widget& b) }

把swap移到新的名字空間了。那麼,像下面的**:

using widgetstuff::widget; widgetw; widgetw2; swap(w, w2);

c++將應用argument-dependent lookup (koenig lookup)規則,進行查詢,最後找到以widget作為引數的swap函式。

從客戶的角度看下面的**:

templatevoid dosomething(t& obj1, t& obj2)

哪乙個swap會被呼叫到呢?有可能是std裡的通用版本;有可能是std裡完全特化的版本;有可能是在某個名字空間裡的過載版本。

如果你想讓它呼叫過載版本,當過載版本不存在,就呼叫std通用版本,那麼可以像下面這樣寫:

templatevoid dosomething(t& obj1, t& obj2)

Item 25 考慮實現乙個不拋異常的swap

swap 函式最初由 stl 引入,已經成為異常安全程式設計的關鍵函式,同時也是解決自賦值問題的通用機制。std 中它的基本實現是很直觀的 namespace std 可以看到,上述 swap 是通過賦值和拷貝構造實現的。所以 std swap 並未提供異常安全,但由於 swap 操作的重要性,我們...

討論 日誌出錯了,應不應該丟擲錯誤

最近一直在想,業務日誌出錯了,應不應該丟擲錯誤?例如以下 12 3shop.addproduct 4log.writelog 新增了一件新商品,物品名為xx,xx 5 public class log 如果log.writelog出現了錯誤,應該丟擲錯誤嗎?若丟擲錯誤,便可以及時發現錯誤,並處理.但...

討論 日誌出錯了,應不應該丟擲錯誤

最近一直在想,業務日誌出錯了,應不應該丟擲錯誤?例如以下 12 3shop.addproduct 4log.writelog 新增了一件新商品,物品名為xx,xx 5 public class log 如果log.writelog出現了錯誤,應該丟擲錯誤嗎?若丟擲錯誤,便可以及時發現錯誤,並處理.但...