在哪里可以找到标准容器和算法的所有例外保证?
-
13-12-2019 - |
解决方案
阅读标准可能会让人感到害怕(让我们回到标准),但是 Bjarne Stroustrup 在他的《C++ 编程语言》一书中就这个主题编写了一个非常好的附录。他将此附录发布于
http://www.stroustrup.com/3rd_safe0.html , 在http://www.stroustrup.com/3rd_safe.pdf
它相当长且详细(而且写得很好)。例如,您可能会发现 E.4 节很有趣,引用:
E.4 标准集装箱保证
如果图书馆操作本身会引发异常,则可以并且确实可以确保其操作的对象保持在定义明确的状态。例如,at()向矢量抛出out_of_range(第16.3.3节)并不是矢量例外安全性的问题。AT()的作者没有问题,请确保向量在投掷之前处于明确的状态。
此外,E.4.1 节规定
除了基本保证外,标准库还为插入或删除元素的一些操作提供了强大的保证。
看看956页。它包含向量、双端队列、列表和映射的各种操作的保证表。总之,这些容器上的所有操作要么是无抛出的,要么是强的,除了 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.4和23.3.6.5)本条款中定义的所有容器类型符合以下其他要求:
- 如果在插入单个元素时通过插入()或emplace()函数抛出异常,则该函数没有效果。
- 如果通过push_back()或push_front()函数抛出异常,则该函数没有效果。
- no erase(),clear(),pop_back()或pop_front()函数会引发异常。
- 返回迭代器的复制构造函数或分配运算符会引发异常。
— 没有 swap() 函数抛出异常。
- 没有Swap()函数无效任何参考的引用,指针或迭代器,引用了要交换的容器的元素。
上面提到的各个部分中指出的怪癖(每个称为异常安全保证)主要是关于特殊的极端情况,例如处理包含类型的散列、比较操作以及抛出交换和抛出移动的异常时运营。
其他提示
n3376
23.2.1一般容器要求[Container.Requirements.general]
第10段
除非另有说明(见23.2.4.1,23.2.5.1,23.3.3.4和23.3.5)本条款中定义的所有容器类型符合以下附加要求:
- 如果插入单个元素的同时抛出Insert()或Emplace()函数,则该函数没有效果。
- 如果由push_back()或push_front()函数抛出异常,则该函数没有效果。
- 没有erase(),clear(),pop_back()或pop_front()函数抛出异常。
- 返回迭代器的副本构造函数或赋值运算符抛出异常。
- 没有Swap()函数抛出异常。
- 没有Swap()函数使任何引用,指针或迭代器无效,引用被交换的容器的元素。
[注意:结束()迭代器不引用任何元素,因此它可能无效。 - endnote]
23.2.4关联容器[关联.Reqmts]
23.2.4.1例外安全保障[Assocative.reqmts.except]
1对于关联容器,没有clear()函数抛出异常。擦除(k)不会抛出异常,除非容器的比较对象(如果有的话)抛出异常。
2对于关联容器,如果在插入或emplace函数内插入单个元素的任何操作抛出异常,则插入无效。
3对于关联容器,没有交换函数抛出异常,除非容器比较对象的交换(如果有的话)抛出该例外。
23.2.5无序关联容器[unord.req]
23.2.5.1异常安全保障[UNORD.REQ.EXCEPT]
1对于无序关联容器,没有Clear()函数抛出异常。擦除(k)不会抛出异常,除非容器的哈希或PRED对象(如果有的话)抛出异常。
2对于无序关联容器,如果通过从插入或emplace函数中插入单个元素的emplate函数以外的任何操作抛出异常,则插入无效。
3对于无序关联容器,除非容器哈希或PRED对象的交换(如果有的话)抛出该例外,否则没有交换函数抛出异常。 4对于无序关联容器,如果从容器的哈希函数或比较函数以外的rehash()函数中抛出异常,则Rehash()函数没有效果。
23.3.3.4排放调节剂[deque.modifiers]
void push_back(t && x);第2段
备注:如果除了通过复制构造函数抛出异常,移动构造函数,赋值运算符或移动的转移分配运算符没有效果。如果由非复制因素t的移动构造函数抛出异常,则效果未指定。
迭代器擦除(Const_iterator First,Const_iterator最后);第6段
抛出:除非由复制构造函数,移动构造函数,分配运算符或移动t的分配运算符抛出异常,否则无例外。
23.3.6.5载体修饰符[vector.modifiers]
void push_back(t && x);第2段
如果由非复制因素t的移动构造函数抛出异常,则效果未指定。
迭代器擦除(Const_iterator First,Const_iterator最后);第5段
抛出:除非由复制构造函数,移动构造函数,分配运算符或移动t的分配运算符抛出异常,否则无例外。
您链接到的文档,N3337标准标准,可作为官员视为官方。这是C ++ 11标准加上未成年人的变化。
你只需要学习阅读标准,这是可以理解的,因为它并非易于阅读。
要查找任何特定库操作的例外保证,请检查操作的备注和评论的规范。如果该函数是成员函数,则检查类型的类型,以了解异常安全性以及它满足的要求。然后检查必须由对象制作以满足这些要求的例外保证的满足要求。对于通用类型和算法还检查在模板参数上的要求,以便查看这些类型必须满足的要求,以便为包含类型或算法或成员函数所做的所有例外保证(如果是模板参数不符合指定的要求,然后使用与这些参数的模板具有未定义的行为,并且均未适用模板规格)。