2013-08-03 75 views
1

我有異常安全和STL容器/迭代器的問題。C++迭代器異常安全

我承擔了一些原因,簡單的容器的迭代器上執行算術運算時

std::vector<POD Type> 

不拋出異常(或DEREF。它)只要你留在區間[開始(), 結束())。我試圖用標準來看(使用N3337),但是我發現沒有給出這樣的保證(但也許我錯過了一些東西!)。另請參閱:May STL iterator methods throw an exception

到現在爲止,我寫了一些相當普遍的代碼,考慮到即使對於具有合理元素類型的簡單容器也沒有提供不保證的保證。

例如像下面可能仍然拋出一個異常(其中c是一個std :: vector的實例):

for(... i = c.begin(); i != c.end(); ++i) { /* do something here - guaranteed to not throw. */ } 

但這招在不同的性病庫,因爲你有例外安全和程序的穩定性問題據我所知,瞭解迭代器操作的實現。

例如,使用Boost.Graph的鄰接列表的clear()函數(並且Boost中還有更多這樣的例子),假設容器m_vertices是std :: vector之類的std序列容器。

inline void clear() { 
for (typename StoredVertexList::iterator i = m_vertices.begin(); // begin() and copy assignement does not throw (according to the STD) 
    i != m_vertices.end(); ++i) // ++i and operator !=() might throw 
     delete (stored_vertex*)*i; // *i might throw 
    m_vertices.clear(); // will not throw (nothrow per Definition of the STD) 
    m_edges.clear(); // same 
} 

此功能應保證不丟,因爲這就是所謂的adjacency_list <的析構函數...>,這將是合理的假設,沒有明確的()函數拋出,即使我沒有找到Boost.Graph文檔中的任何異常安全保證。

我希望你能揭示一下這個異常安全問題,並告訴我我在這裏失去了什麼。特別是對於什麼樣的迭代器算術運算和解引用實際上不是拋出以及定義了哪些保證。

謝謝!

從C++ STD紙N3337

23.2.1:10)

除非另有規定(參見23.2.4.1,23.2.5.1,23.3.3.4和23.3.6.5)所有的容器類型定義在此 子句中滿足以下附加要求:

- 如果insert()或emplace()函數在插入單個元素時引發異常,那麼 函數不起作用。

- 如果push_back()或push_front()函數引發異常,則該函數不起作用。 (),clear(),pop_back()或pop_front()函數拋出異常。

- 返回的迭代器的拷貝構造函數或賦值操作符拋出異常。

- no swap()函數拋出異常。

- 沒有swap()函數使任何引用,指針或迭代器都指向正在交換的容器的元素。

[注意:end()迭代器不引用任何元素,因此可能會使 無效。 - 注意]

+0

不支持在迭代容器時調用container.erase()。如果你這樣做,一個實現可能會簡單地崩潰或者可能拋出一個異常。 –

+0

brian beuning:我不確定你在說什麼 - 這與我的問題有關嗎?但是在迭代像STD序列容器之類的容器時調用擦除操作完全有效! – livingissuicide

+0

查看http://stackoverflow.com/questions/6438086/iterator-invalidation-rules –

回答

2

只有廣泛的合同(即不可能失敗的操作)才能得到保證。所有迭代器操作都有狹窄的契約(即它們有一些先決條件),因此,在不滿足前提條件時可能會以任意方式失敗。因此,它們沒有任何異常保證,因爲未定義的行爲前提條件未得到滿足可能導致給定的實現引發異常。假設滿足前提條件並且行爲不包括引發任何異常,那麼各個迭代器操作的行爲可以很好地定義:迭代器操作的行爲在需求表中定義。

這就是說,一般來說,你應該期待所有的操作可能會放在第一位。要從異常中進行適當的恢復:但是,有時需要知道特定函數不會拋出,否則恢復可能會失敗,因此某些基本操作(如交換內置類型的兩個對象)被定義爲不拋出。

+0

看起來像我錯過了C++標準的基本點。但是,這需要我相當長的一段時間才能弄清楚。謝謝你,先生,這個出色的答案! – livingissuicide

+0

對於大多數迭代器([counterexample](http://stackoverflow.com/a/7903037/3919155))的Afaik唯一(可疑的)良好的用於這種未定義的行爲所造成的前提條件不滿足拋出的異常將是一些用於調試目的的頂級代碼。我認爲這可能會導致性能下降,但以稍微好一點的調試爲代價。我希望標準庫開發人員無論如何都允許爲迭代器使用'noexcept'。 – jotik