I have a problem with exception safety and STL containers/iterators.
I assumed for some reason that an iterator of the simple container
std::vector<POD Type>
is not throwing an exception when performing arithmetic operations on it (or deref. it) as long as you stay within the interval [begin(), end()). I tried to look that up in the standard (using N3337) but i have found that no such nothrow guarantees are given (but maybe i missed something!). Also see: May STL iterator methods throw an exception
Until now I wrote quite some code that would be broken in general, taking into account that there are no said nothrow guarantees even for simple containers with reasonable element types.
For example something like the following might still throw an exception (whereby c is a std::vector instance):
for(... i = c.begin(); i != c.end(); ++i) { /* do something here - guaranteed to not throw. */ }
But this incurs exception safety and program stability problems across different STD libraries since you have to know the implementations of the iterator operations as far as I can see.
For example take the clear() function of Boost.Graph's adjacency list (and there are many more such examples within Boost) and suppose the container m_vertices is a std sequence container like std::vector.
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
}
This function should be guaranteed to not throw since it is called in the destructor of adjacency_list<...> and it would be reasonable to assume that no clear() function throws, even though I did not find any exception safety guarantees in the docs of Boost.Graph.
I hope you can shed some light onto this exception safety issue and show me what I am missing here. Especially for what kind of iterators arithmetic operations and dereferencing is really not throwing and where such guarantees are defined.
Thanks!
From the C++ STD Paper N3337
23.2.1:10)
Unless otherwise specified (see 23.2.4.1, 23.2.5.1, 23.3.3.4, and 23.3.6.5) all container types defined in this Clause meet the following additional requirements:
— if an exception is thrown by an insert() or emplace() function while inserting a single element, that function has no effects.
— if an exception is thrown by a push_back() or push_front() function, that function has no effects.
— no erase(), clear(), pop_back() or pop_front() function throws an exception.
— no copy constructor or assignment operator of a returned iterator throws an exception.
— no swap() function throws an exception.
— no swap() function invalidates any references, pointers, or iterators referring to the elements of the containers being swapped.
[ Note: The end() iterator does not refer to any element, so it may be invalidated. —end note ]