看看这段导致程序终止而不会捕获异常的代码。
#include <iostream>
#include <string>
#include <memory>
#include <stdexcept>
using namespace std;
struct test {
~test() noexcept(false) {
throw runtime_error("-my-cool-exception-");
}
};
int main()
{
try {
auto ptr = unique_ptr<test>(new test());
//test t; // this is ok, without unique_ptr<test> it works fine.
}
catch(exception& e) {
cout << "this is not called, the program is aborted";
cout << e.what() << endl;
}
return 0;
}
这个问题与堆栈溢出问题不同:throwing exceptions out of destructor。
不同之处在于,只有当我使用unique_ptr<test>
时才会捕获到异常。
您可以在此处查看实时代码,编辑和编译http://cpp.sh/9sk5m
答案 0 :(得分:13)
标准要求的。根据{{3}}:
要求:表达式get_deleter()(get())应该格式良好,具有明确定义的行为,不应抛出异常。 [注意:使用default_delete需要T为完整类型。 - 结束说明]
(强调我的)
实际上,析构函数本身是否具有noexcept(false)
并不重要。它被禁止投入此案 - 最后一句话。
案例std::
的情况通常如此 - 除非另有说明。根据{{3}}:
特别是,在以下情况下,效果未定义: [...] 如果任何替换函数或处理函数或析构函数通过异常退出,除非在适用的必需行为中明确允许:段落。
(强调我的)
注意:通常,可以使用noexcept(false)
投掷析构函数。但是,这非常危险,因为如果堆栈因抛出异常而展开,将调用 std::terminate
。
根据{{3}}:
当控件从抛出异常的位置传递到处理程序时,析构函数由本节中指定的进程调用,称为堆栈展开。 如果通过堆栈展开直接调用的析构函数以异常退出,则调用std :: terminate([except.terminate])。 [注意:因此,析构函数通常应该捕获异常,而不是让它们从析构函数中传播出来。 - 结束说明]
(强调我的)