- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我读到过,由于堆栈展开,从析构函数中抛出不是一个好主意。我不确定我是否完全理解。所以我尝试了下面的例子
struct foo
{
~foo()
{
throw 1;
}
};
struct bar
{
~bar()
{
throw 2;
}
};
int main()
{
try
{
foo a;
bar b;
throw 3;
}catch(int a)
{
std::cout << a;
}
}
现在我期望 a 将是 1,因为首先抛出 3,然后调用 b 的析构函数,抛出 2,然后调用 a 的析构函数,抛出 1。显然情况并非如此,这可以解释为什么它从析构函数中抛出不是一个好主意。我的问题是为什么 abort() 被称为 b 的析构函数?
最佳答案
在堆栈展开期间抛出异常这将导致调用std::terminate
,其默认操作是调用std::abort
.
CERT在他们的 ERR33-CPP. Destructors must not throw exceptions 中有很好的解释文件说(强调我的):
A destructor is very likely to be called during stack unwinding resulting from an exception being thrown. If the destructor itself throws an exception, having been called as the result of an exception being thrown, then the function std::terminate() is called with the default effect of calling std::abort(). This could provide the opportunity for a denial-of-service attack. Hence, destructors must satisfy the no-throw guarantee, that is, they must not throw an exception if they themselves have been called as the result of an exception being thrown.
C++ 标准草案 15.2
构造函数和析构函数 中对此进行了介绍,其中指出:
The process of calling destructors for automatic objects constructed on the path from a try block to a throw-expression is called “stack unwinding.” If a destructor called during stack unwinding exits with an exception, std::terminate is called (15.5.1). [ Note: So destructors should generally catch exceptions and not let them propagate out of the destructor. —end note ]
请注意,在 C++11 中,析构函数被隐式指定 noexcept(true)
,只要它调用的函数都不允许异常。因此,在这种情况下,无论从析构函数中抛出什么,都会调用 std::terminate
。
来自 12.4
析构函数部分:
A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration (15.4).
和 15.4
说:
An implicitly declared special member function (Clause 12) shall have an exception-specification. If f is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f’s implicit definition; f shall allow all exceptions if any function it directly invokes allows all exceptions, and f shall allow no exceptions if every function it directly invokes allows no exceptions.
理论上你可以使用 std::uncaught_exception在析构函数中但在 GotW #47 中检测堆栈展开 Herb Sutter 解释了为什么这种技术不像看起来那么有用。
尽管 Herb 最近在 N4152: uncaught_exceptions 中提出了一个修复方案
关于c++ - 为什么不能从析构函数中抛出。例子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26395476/
我开始考虑在我 future 的项目或重构中实现控制反转容器,我想知道在正确设计依赖项时哪些原则(除了 GoF 模式)可能需要牢记在心。假设我需要构建一个简单的控制台应用程序,如果它可以访问互联网,它
假设我有一个 RxC contingency table 。这意味着有 R 行和 C 列。我想要一个维度为 RC × (R + C − 2) 的矩阵 X,其中包含行的 R − 1 “主效应”以及列的
我正在尝试使用 DKMS 为正在运行的内核 (4.4) 构 build 备树覆盖。我天真的 Makefile 如下: PWD := $(shell pwd) dtbo-y += my-awsome-o
我有一个 sencha touch 项目。我是用 phonegap 2.9 构建的,并且可以正常工作 device.uuid 返回到设备 ID。当我尝试使用 3.1 device.uuid 构建时抛出
我在安装了 Xcode 4.5.1 的 Mt Lion 上运行。 默认情况下,当我构建并部署到 iOS 5.1 设备时,显示会在我旋转设备时旋转,但当我部署到 iOS 6 模拟器或运行 iOS 的 i
我正在尝试使用 Google Analytics Reporting API v4 构建多折线图。 一张图表,其中我按每天的 session 计数为每个设备(台式机/平板电脑/移动设备)设置了一条线。
我一生都无法使用 xcode 组织者“自动设备配置”中的“团队配置配置文件”在 xcode 4.0.1 中将我的应用程序构建到我的 iPad 上。 该应用程序完美地构建到模拟器,但当我构建到 iPad
我是一名优秀的程序员,十分优秀!