请考虑以下代码:
#include <iostream>
#include <stdexcept>
void foo()
{
throw std::runtime_error("How long do I live?");
}
int main()
{
try
{
foo();
}
catch (std::runtime_error& e)
{
std::cout << e.what() << std::endl;
}
}
为什么我可以通过引用来捕获异常,std::runtime_error("How long do I live?")
是否是右值?
为什么异常对象在catch块中仍然存在?
究竟抛出的异常对象存储在哪里?他们的一生是几岁?
答案 0 :(得分:7)
在C ++标准中,第15.1.4段:
临时副本的内存 被抛出的异常是 以未指明的方式分配, 除非在3.7.3.1中注明。的的 只要存在,临时持续存在 为此执行的处理程序 例外即可。特别是,如果一个 处理程序通过执行throw退出; 声明,将控制传递给 另一个处理程序 例外,所以临时遗体。 当最后一个处理程序被执行时 以任何方式退出例外 除了投掷;临时对象 被破坏和实施 可能会释放内存 临时对象;任何这样的 解除分配是在未指定的情况下完成的 办法。破坏发生了 毁灭后立即 在...中声明的对象 处理程序中的异常声明。
请注意,在C ++ - 标准对话中,处理程序表示具有正确参数类型的catch
块。
答案 1 :(得分:5)
抛出的异常不是临时的 - 编译器生成的异常代码会保留它的永久副本。所以你可以将它绑定到非const引用。
[编辑] 我只是检查标准,它实际上是指临时副本。但是,临时的生命周期保证至少与异常处理程序的生命周期一样长。
答案 2 :(得分:2)
正如尼尔所说,内部编译器魔法正在进行中。另外,请注意允许编译器创建异常对象的any number of copies。
答案 3 :(得分:1)
感谢您试图了解该语言的细节。与此同时,恕我直言,了解为什么 应该通过引用捕获异常(并按值抛出),而不是可以的原因。 / p>
人们通常使用异常类的层次结构,并且通过引用捕获允许您在不需要单独处理单个异常类型时利用多态性并捕获基类的异常。如果您无法通过引用捕获,则必须为可能在catch
子句中抛出的每种可能类型的异常编写try
子句。