当我查看有关cppreference的Container
要求时,会将Destructible
列为value_type
的要求。这似乎意味着容器元素的析构函数可能不会抛出。
我还没有能够在C ++ 14标准中找到这个要求的引用(在旧版本中看不到)。我唯一能找到的是value_type
必须是Erasable
,并不代表任何异常安全。
所以我的问题是,std::vector
中的元素可能有抛出析构函数吗?如果没有,标准中的哪个部分禁止它?
P.S。:不用担心,我不打算用抛出析构函数创建类型。我只是编写一个符合标准的实现,并试图获得异常安全权。
答案 0 :(得分:4)
N4140 [res.on.functions] / 2州:
特别是,在以下情况下效果未定义:
(2.1) - 对于替换函数(18.6.1),如果安装的替换函数没有实现适用的必需行为的语义:段落。
(2.2) - 对于处理函数(18.6.2.3,18.8.3.1,D.11.1),如果安装的处理函数没有实现适用的必需行为的语义:段落
(2.3) - 对于在实例化模板组件时用作模板参数的类型,如果对该类型的操作没有实现适用的Requirements子句的语义(17.6.3.5,23.2,24.2,26.2)。除非另有说明,否则此类操作可以通过抛出异常来报告失败。
(2.4) - 如果有任何替换函数或处理函数或析构函数退出 例外,除非在适用的必要行为中明确允许:段落。
(2.5) - 如果在实例化模板组件时将不完整类型(3.9)用作模板参数,除非特别允许该组件。
这有点模糊,但节省了大量空间,否则会浪费在" T
必须满足可破坏的要求"整个图书馆条款的陈述。
值得注意的是,这并不意味着std::vector
的元素不具有抛出析构函数;它只意味着当从标准库调用时,所述析构函数必须永远不会抛出。所以例如这个程序符合:
#include <vector>
struct A {
bool throw_an_int = false;
~A() noexcept(false) {
if (throw_an_int) throw 42;
}
};
int main() {
try {
A a;
a.throw_an_int = true;
std::vector<A> lots_of_As(42);
} catch(int&) {}
}
答案 1 :(得分:1)
是。†标准在一般要求中说明了这一点:
<子> [C++11: §23.2.1/10]:
子>
除非另有说明(见23.2.4.1,23.2.5.1,23.3.3.4和 23.3.6.5)本条款中定义的所有容器类型均满足以下附加要求:
- 没有erase(),clear(),pop_back()或pop_front()函数抛出异常。
使用clear
函数作为示例(由于它不是一般要求的例外),它具有以下要求:
销毁a中的所有元素。使引用a元素的所有引用,指针和迭代器无效并且可能使过去的迭代器无效。发布:
a.empty()
返回true
这意味着它基本上在所有元素上调用std::allocator_traits<Alloc>::destroy
。如果t->~T()
不可用,则委托给a.destroy(t)
。但是,这隐含地保证a.destroy(t)
和t->~T()
都不应该抛出,因为它会违反clear
强noexcept
规范:
// § 23.3.6.1
void clear() noexcept;
因此,通过演绎,我们可以断言析构函数可以抛出但是必须通过某种机制来抑制它们,例如将它们包装在try-catch块中。
†:经过进一步检查,似乎析构函数可以抛出,但必须按照以下评论中的说明禁止例外。