【问题标题】:May STL iterator methods throw an exception可能 STL 迭代器方法抛出异常
【发布时间】:2011-12-15 16:35:13
【问题描述】:

Destructors may not throw exceptions(所以stack unwinding可以在异常处理期间完成),并且必须解除分配给对象的所有资源(所以没有资源泄漏)。包含多个其他对象(或分配了多个资源)的对象设计可能会在 STL 容器中记录指向它们的指针。因此,析构函数将使用以下与迭代器相关的方法:

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

但要保证析构函数既不抛出异常又释放其资源,您需要依赖那些从不抛出异常的方法。

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


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

【问题讨论】:

  • “在底层,STL 迭代器本质上是一个指针”——你永远不应该依赖这个假设。概念是基于指针,但不一定是实现。
  • 析构函数可能会抛出异常,实际上......只要它们捕获它们:)。规则是“异常不能传播析构函数”。
  • 规则甚至不是这样,它是“如果异常从析构函数中传播出来,程序将在某些条件下terminate”。而且我认为它在某些条件下也可能有 UB,如果被破坏的对象是数组和/或容器的一部分,我不记得了。您是否认为terminate 是您的程序可接受的消亡取决于程序,但很明显,如果您编写的组件应该易于重用,那么您会避免使用它。

标签: c++ exception stl


【解决方案1】:

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

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

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

【讨论】:

  • 如果是std::vector< Resource >,是的。但不是std::vector< Resource * >
  • @Raedwald:我已经扩展了我的答案。应该使用适当的资源管理类来涵盖这种情况。
  • shared_ptr, unique_ptr, Boost:我问的是标准 C++ 2003。
  • @JoachimPileborg:您不能将auto_ptr 放入标准容器中。
  • 因为你可能不会创建std::auto_ptr的STL容器见stackoverflow.com/questions/111478/…
【解决方案2】:

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

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

顺便说一句。我是23.1.10

【讨论】:

  • 留下增量和取消引用运算符,以及begin() and end()`。
  • @Raedwald 我不认为标准要求迭代器操作是非抛出的。
【解决方案3】:

operator++ 用于有效的迭代器

C++ 标准(我参考 N3290 草案)不保证迭代器的增量运算符。

例如,std::istreambuf_iterator::operator++ 会调用 std::basic_streambuf::sbumpcsbumpc 可能会调用 uflow,这反过来可能会引发异常。

【讨论】:

  • 我很欣赏 MSalters 和 Raedwald
  • 然而,这是指定的行为,即要求istreambuf_iterator::operator++ 具有此效果。但重要的是,如果sbumpc 没有,操作员不应该抛出异常。这通常是正确的 - 定义范围(容器)上的迭代器在该范围内递增时不能随意抛出异常。否则,实现可以简单地总是抛出异常并且仍然​​满足规范的要求。
【解决方案4】:

根据http://www.tenouk.com/Module31.html,这些操作(对于 '*' 和 '->' 它还取决于存储的类型)对于 STL 容器是不会抛出的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 2011-02-04
    • 1970-01-01
    • 2010-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多