在哪里可以找到标准容器和算法的所有异常保证?

时间:2012-07-28 07:12:22

标签: c++ exception standard-library c++-faq exception-safety

是的,我查看了我能找到的C++ standards(或草稿),但我没有找到任何全面的STL容器提供的异常保证。我所能找到的只是偶然的部分,对某些类型的某些函数描述不完整。或许它就在那里,但我只是找不到它,我不知道。

注意: 要求列出人们可以想到的所有保证,基本上是{{3 }}。
我正在寻找此信息本身的权威来源 - 或者最好是源代码的免费版本(例如标准草案),我或多或少可以将其视为官方信息。

3 个答案:

答案 0 :(得分:14)

阅读标准可能会让人感到害怕(让我们回到标准),但是Bjarne Stroustrup在他的“The C ++ Programming Language”一书中写了一篇关于这个主题的非常好的附录。他在

发布了这个附录

http://www.stroustrup.com/3rd_safe0.html,at http://www.stroustrup.com/3rd_safe.pdf

它非常详细(并且写得很好)。例如,您可以找到有趣的E.4节,引用:

  

E.4标准集装箱保证

     

如果库操作本身抛出异常,它可以 - 并且确实 -   确保它所操作的对象留在一个   定义明确的国家。例如,at()抛出out_of_range为a   向量(第16.3.3节)不是向量异常安全的问题   。 at()的作者没有问题确保向量在一个   投掷之前定义明确的状态。

此外,第E.4.1节说明

  

除了基本保证外,标准库还提供   对于插入或删除元素的一些操作的强有力保证。

查看第956页。它包含一个表,用于vector,deque,list和map的各种操作。 总之,这些容器上的所有操作都不是强大的,除了 N - 元素插入到地图之外,它提供了基本的保证。

注意:上面的文字很旧,并没有解决C ++ 11,但对于大多数目的和目的来说仍然应该是正确的。

谈到C ++ 11 ......

标准首先说明了关于容器的问题 array, deque, forward_list, list, vector, map, set, unordered_map, unordered_set, queue,stack:  在

<强> 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()函数使任何引用,指针或   迭代器引用被交换的容器的元素。

上面提到的各个部分(每个部分称为异常安全保证)中指出的怪癖主要是关于特殊的反墙情况,例如处理包含类型的哈希,比较操作以及抛出交换的异常时并投掷移动操作。

答案 1 :(得分:8)

n3376

23.2.1一般容器要求[container.requirements.general]

第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()迭代器不引用任何元素,因此它可能无效。 -endnote]

23.2.4关联容器[associative.reqmts]

23.2.4.1异常安全保证[associative.reqmts.except]

  

1对于关联容器,没有clear()函数抛出异常。 erase(k)不会抛出异常,除非容器的Compare对象(如果有)抛出该异常   2对于关联容器,如果插入或插入单个元素的插入或插入函数中的任何操作抛出异常,则插入无效。
  3对于关联容器,除非交换容器的Compare对象(如果有)抛出异常,否则交换函数不会抛出异常。

23.2.5无序关联容器[unord.req]

23.2.5.1例外安全保证[unord.req.except]

  

1对于无序关联容器,没有clear()函数抛出异常。 erase(k)不会抛出异常,除非容器的Hash或Pred对象(如果有)抛出该异常。
  2对于无序关联容器,如果插入或插入单个元素的插入或插入函数中的容器的散列函数以外的任何操作抛出异常,则插入无效。
  3对于无序关联容器,除非交换容器的Hash或Pred对象(如果有)抛出异常,否则交换函数不会抛出异常。
  4对于无序关联容器,如果从rehash()函数中抛出异常而不是容器的散列函数或比较函数,则rehash()函数无效。

23.3.3.4 deque modifiers [deque.modifiers]

void push_back(T&amp;&amp; x);第2段

  

备注:如果除了复制构造函数之外抛出异常,则移动构造函数,赋值运算符或T的移动赋值运算符没有任何影响。如果非CopyInsertable T的移动构造函数抛出异常,则效果未指定。

iterator erase(const_iterator first,const_iterator last);第6段

  

抛出:除非复制构造函数,移动构造函数,赋值运算符或T的移动赋值运算符抛出异常,否则无效。

23.3.6.5向量修饰符[vector.modifiers]

void push_back(T&amp;&amp; x);第2段

  

如果非CopyInsertable T的移动构造函数抛出异常,则效果未指定。

iterator erase(const_iterator first,const_iterator last);第5段

  

抛出:除非复制构造函数,移动构造函数,赋值运算符或T的移动赋值运算符抛出异常,否则无效。

答案 2 :(得分:2)

您链接到的文件,n3337标准草案,可以视为正式文件。它是C ++ 11标准加上次要的编辑修改。

你只需要学习阅读标准,这是可以理解的,因为它并不容易阅读。

要查找任何特定库操作的异常保证,请检查该操作的说明以获取有关异常的注释和注释。如果该函数是成员函数,则检查类型的规范以获得有关异常安全性的注释以及它满足的要求。然后检查对象必须做出的异常保证的满足要求,以满足这些要求。

对于泛型类型和算法,还要检查对模板参数的要求,以便了解这些类型必须满足哪些要求才能保持类型或算法或成员函数所做的所有异常保证(如果模板参数不符合指定的要求,然后使用带有这些参数的模板具有未定义的行为,并且不适用模板的规范。