我对异常安全和 STL 容器/迭代器有疑问。
由于某种原因,我假设简单容器的迭代器
std::vector<POD Type>
只要您保持在区间 [begin(), end()) 内,就不会在对其执行算术运算(或取消引用它)时引发异常。我试图在标准中查找它(使用 N3337),但我发现没有给出这样的 nothrow 保证(但也许我错过了一些东西!)。另请参阅:May STL 迭代器方法抛出异常
到现在为止,我写了很多通常会被破坏的代码,考虑到即使对于具有合理元素类型的简单容器也没有说不可以保证。
例如,以下内容可能仍会引发异常(其中 c 是 std::vector 实例):
for(... i = c.begin(); i != c.end(); ++i) { /* do something here - guaranteed to not throw. */ }
但这会导致跨不同 STD 库的异常安全和程序稳定性问题,因为据我所知,您必须了解迭代器操作的实现。
例如,以 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<...> 的析构函数中调用的,并且假设没有 clear() 函数抛出是合理的,即使我在文档中没有找到任何异常安全保证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() 函数抛出异常,则该函数无效。
— 没有erase()、clear()、pop_back() 或pop_front() 函数抛出异常。
— 返回的迭代器的任何复制构造函数或赋值运算符都不会引发异常。
— 没有 swap() 函数抛出异常。
— 没有 swap() 函数会使任何引用被交换容器元素的引用、指针或迭代器失效。
[ 注意: end() 迭代器不引用任何元素,因此它可能会失效。——尾注]