2013-12-22 72 views
3

我目前正在編寫異常安全的代碼,並且我的設計不需要爲 set :: find方法提供保證。 我假設比較對象總是成功。 它意味着set :: find方法會一直成功嗎?std :: set ::查找異常保證

在我看到http://en.cppreference.com/w/cpp/container/set/erase後,我想到了這樣一種可能性,set :: erase方法,具有相同的假設,應該總是成功,也許有一個發現它(然後它將definetely值得評論文檔!)

問題的直接來源是我需要檢查一個元素是否在一個集合中,並從集合中刪除它 - 所有沒有保證(它在一個catch塊中)。

+0

我不確定標準或任何保證集或任何stl容器,但我會說這個..有一次我調用vector :: erase(v.end())..它拋出一個異常..我花了數小時試圖找出原因。原來我的矢量是空的。不知道這是否仍然發生,或者如果std :: set有這個問題,但它發生在我在gcc 4.8.1 for windows ..我結束了必須做一個if語句檢查,如果'vector :: find!= v.end ()'。我想你可能必須這樣做。這可能是唯一一次你沒有確定的例外嗎? – Brandon

+0

@CantChoose這是一個未定義的行爲,對於一個空向量和一個非空向量一樣多。你不能抹掉第一個元素過去的結尾...... – IInspectable

+0

@CantChooseUsernames你應該很高興它拋出一個異常。這是未定義行爲AFAIK,可能已經擦除了您的硬盤驅動器;) – dyp

回答

1

std::set::find

返回值

迭代器與主要key的元素。如果沒有找到這樣的元素,則返回迭代器的末尾(參見end())。

文檔和C++標準都沒有明確列出任何異常安全保證。然而,闡明瞭std::set::erase相同的規則適用於這裏(§23.2.4.1異常安全保證[associative.reqmts.except]):

erase(k)除非異常是由容器的Compare對象拋出不拋出異常(如果有的話)。

本質上,除非Compare對象拋出異常,否則std::set::find不會拋出。 Bjarne Stroustrup在The C++ Programming Language, Special Edition - Appendix E有如下說:

幸運的是,謂詞很少做任何可能會引發異常的東西。但是,在考慮異常安全性時,必須考慮用戶定義的<==!=謂詞。

如果您未提供任何用戶定義的謂詞,則可以假定std::set::find不會引發異常。如果是,則應將其標記爲noexcept以在您的方案中安全地工作。

0

C++ 11 §23.2.4.1異常安全性的保證[associative.reqmts.except]列出了所有關聯容器(包括set)並且不存在由find提及異常安全要求。所以不行,標準不保證find從不拋出。

在沒有未定義的行爲和假設一個非拋出比較器的情況下,我發現極不可能存在C++標準庫的實現,它會拋出來自set::find的異常。我個人是舒服(a)在noexcept轉發功能包裝set::find因此,如果這樣一個「不可能」的事情不斷髮生程序會崩潰,或者(b)包裹在

auto it = foo.end(); 
try { 
    it = foo.find(bar); 
} catch(...) {} 

和特定set::find通話簡單地將異常視爲「未找到」。

請注意,關聯容器的排序關係是一個容易忽略的未定義行爲來源:§23.2.4/2要求排序關係對關鍵元素產生嚴格的弱排序(如§25.4所述)。一個關聯容器,其實例化的訂購關係是而不是嚴格的弱排序沒有定義的行爲,其中一個可能的結果是從find引發異常。

+0

我很容易想象如果比較器沒有正確返回對象的嚴格弱排序時拋出異常。我敢打賭,Dev Studio可能會。 – StilesCrisis

+0

@StilesCrisis是的,引發異常是程序中未定義行爲的可能結果,正如其他任何可想象的結果一樣。 – Casey

+0

編寫我的操作符<始終返回false是不合邏輯的,但它的表面不會拋出。獨自一人,這不是未定義的行爲 - 這只是不正確的結果。 – StilesCrisis