考虑以下简单的C ++代码:
void foo() {
throw(my_exception());
}
void check_exc(const my_exception &exc) {
/* Do stuff with exc */
}
void bar() {
try {
foo();
} catch(const my_exception &exc) {
check_exc(exc);
}
}
在bar
的异常处理程序中,exc
引用的异常如何仍然存在,看看它是如何在foo
的堆栈帧中分配的?在异常处理程序运行时,该帧是否应该被解除,并且在那里分配的任何值都已经被认为是死的?特别是因为我明确地调用了另一个需要堆栈空间的函数。
作为一名试图学习C ++的C程序员,我在这里误解了什么?这些不同的值实际上存在于内存中,更准确地说是什么?
答案 0 :(得分:7)
在throw-expression中创建的临时用于初始化异常对象本身,(引用标准)"以未指定的方式分配"。该对象持续(至少)直到处理了异常,因此处理程序对它的引用在处理程序或从处理程序调用的任何函数中都是有效的。
答案 1 :(得分:3)
按值抛出异常。
即,复制指定的对象(可能会切片,与任何复制初始化一样)或移动。
您可以通过以下方式引用的例外对象 catch
子句的引用参数未在原始投掷代码的堆栈帧中分配,而是以“未指定的方式”分配。
在C ++ 11中,由于要求异常对象可以由本质上共享的所有权智能指针std::exception_ptr
引用,因此限制了异常对象可能的分配方式(在运行时库内部)。
共享所有权的可能性意味着在C ++中,异常对象可以在完成的异常处理之后具有有保证的生命周期。
这主要是为了支持通过非异常感知的C代码传递异常,以及传递嵌套的异常信息。
答案 2 :(得分:1)
实施因平台而异。生命周期比人们想象的更复杂,因为throw语句在foo()的堆栈框架中开始执行。
异常对象可能会获得副本并重新分配,或者catch块可能在foo顶部的框架中执行,但是带有指向条形框架的指针以引用条形变量。
答案 3 :(得分:0)
他,
行
throw(my_exception())
生成my_exception类型的新对象。您可以指定所需的任何内容(int,enums,char *或类)。当然,类更有意义,因为您可以为其定义其他数据。
在此之后,将清理整个堆栈并终止所有递归,直到它到达第一个 try / catch 块。那个例外仍然存在。 catch 块中的代码就像实现 if / else 块一样,只是更聪明一些。
欢呼声,