STL 迭代器方法可能会引发异常

May STL iterator methods throw an exception

提问人:Raedwald 提问时间:10/26/2011 最后编辑:CommunityRaedwald 更新时间:11/21/2015 访问量:6308

问:

析构函数可能不会引发异常(因此堆栈展开可以在异常处理期间完成),并且必须释放分配给对象的任何资源(因此不会泄漏资源)。包含多个其他对象(或分配了多个资源)的对象的设计可能会在 STL 容器中记录指向这些对象的指针。因此,析构函数将使用以下与迭代器相关的方法:

  • begin(),用于容器end()
  • operator++对于有效的迭代器
  • operator*或对于有效的迭代器operator->

但是,为了保证析构函数既不会引发异常,又会释放其资源,您需要依赖这些方法,从不引发异常。

依靠这些从不抛出异常的方法是否安全?很难想象一个实际的实现会引发异常,因为在后台,STL 迭代器本质上是一个指针。但是,标准 C++ 是否要求这些方法从不引发异常?我在 C++ 标准中没有找到明确的声明。


编辑:有趣的情况是 C++ 03 当你想要一个指向资源的指针容器时。这样做是有充分理由的;例如,如果您有多态资源。正如 Björn Pollex 在他的回答中指出的那样,如果您使用资源容器(例如 )而不是指向资源的指针容器,则容器的析构函数将为您处理对象的销毁(释放)。std::list< Resource >Resource

C++ 异常 STL

评论

3赞 mloskot 10/26/2011
“就像在引擎盖下一样,STL 迭代器本质上是一个指针”——你永远不应该依赖这个假设。这个概念是基于指针的,但不一定是实现。
0赞 Kos 10/26/2011
析构函数可能会引发异常,实际上...只要他们抓住他们:)。规则是“异常不能从析构函数中传播”。
0赞 Steve Jessop 10/26/2011
规则甚至不是这样,而是“如果异常从析构函数传播出来,程序将在某些条件下传播”。而且我认为它在某些条件下也可能有 UB,如果被破坏的对象是数组和/或容器的一部分,我不记得了。你是否认为你的程序可以接受的消亡取决于程序,尽管很明显,如果你正在编写应该很容易重用的组件,那么你会避免它。terminateterminate

答:

1赞 Björn Pollex 10/26/2011 #1

因此,析构函数将使用以下与迭代器相关的迭代器 方法

不,它不会。该对象的析构函数只会调用容器的析构函数,而容器的析构函数又可以保证不会引发异常。

如果正确使用 RAII,几乎不会遇到必须显式释放资源的情况。这可以通过让容器存储或 或使用 Boost.Pointer Container 之类的东西来实现。shared_ptrunique_ptr

评论

0赞 Raedwald 10/26/2011
如果是 ,是的。但不是在 .std::vector< Resource >std::vector< Resource * >
0赞 Björn Pollex 10/26/2011
@Raedwald:我已经扩展了我的答案。应通过使用适当的资源管理类来涵盖此方案。
1赞 Raedwald 10/26/2011
shared_ptr,,Boost:我问的是标准的C++ 2003。unique_ptr
6赞 Björn Pollex 10/26/2011
@JoachimPileborg:你不能把一个放到一个标准容器里。auto_ptr
1赞 Raedwald 10/27/2011
由于您可能无法创建 STL 容器的原因,请参阅 stackoverflow.com/questions/111478/...std::auto_ptr
6赞 Šimon Tóth 10/26/2011 #2

返回的迭代器的复制构造函数或赋值运算符不会引发异常

这是来自C++03标准。我不认为标准比这更进一步。

顺便说一句,这是23.1.10

评论

0赞 Raedwald 10/26/2011
保留 increment 和 dereference 运算符,以及 end()'。begin() and
0赞 Šimon Tóth 10/26/2011
@Raedwald 我不认为该标准要求迭代器操作是非抛出的。
18赞 mloskot 10/26/2011 #3

operator++ 表示有效的迭代器

C++标准(我指的是N3290草案)不为迭代器的增量运算符提供无抛出保证。

例如,调用 中的效果。可能调用,而这反过来可能会引发异常。std::istreambuf_iterator::operator++std::basic_streambuf::sbumpcsbumpcuflow

评论

0赞 mloskot 10/27/2011
我很欣赏 MSalters 和 Raedwald
2赞 davmac 11/21/2015
但是,这是指定的行为,即需要具有此效果。但重要的是,如果没有,操作员不应抛出异常。这通常是正确的 - 在定义范围(容器)上的迭代器不能在该范围内递增时任意抛出异常。否则,实现可能总是抛出异常,但仍满足规范的要求。istreambuf_iterator::operator++sbumpc
0赞 kitek 12/23/2013 #4

根据 http://www.tenouk.com/Module31.html 这些操作(对于“*”和“->”,它也取决于存储的类型)对于 STL 容器来说是没有的。