简体   繁体   English

C ++中抛出异常的生命周期

[英]Lifecycle of thrown exceptions in C++

Consider the following simple C++ code: 请考虑以下简单的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);
    }
}

In bar 's exception handler, how comes the exception referenced by exc is still alive, seeing as how it was allocated in foo 's stack frame? bar的异常处理程序中, exc引用的异常如何仍然存在,看看它是如何在foo的堆栈帧中分配的? Shouldn't that frame have been unwound by the time the exception handler gets to run, and any values allocated there already be considered dead? 在异常处理程序运行时,该帧是否应该被解除,并且在那里分配的任何值都已经被认为是死的? Especially so since I'm explicitly calling another function which would need that stack space. 特别是因为我明确地调用了另一个需要堆栈空间的函数。

As a C programmer trying to learn C++, what am I misunderstanding here? 作为一名试图学习C ++的C程序员,我在这里误解了什么? Where do these various values actually exist in memory, more precisely? 这些不同的值实际上存在于内存中,更确切地说是什么?

The temporary created in the throw-expression is used to initialise the exception object itself, which (to quote the standard) "is allocated in an unspecified way". 在throw-expression中创建的临时用于初始化异常对象本身,(引用标准)“以未指定的方式分配”。 That object lasts (at least) until the exception has been handled, so the handler's reference to it is valid within the handler, or any function called from the handler. 该对象(至少)持续到处理异常为止,因此处理程序对它的引用在处理程序或从处理程序调用的任何函数中都是有效的。

Exceptions are thrown by value . 例外是按价值抛出

That is, the specified object is copied (possibly sliced, as with any copy initialization) or moved. 也就是说,复制指定的对象(可能是切片,与任何复制初始化一样)或移动。

The exception object that you can reference via eg a catch clause's reference parameter, is not allocated in the original throwing code's stack frame, but in “an unspecified way”. 您可以通过例如catch子句的引用参数引用的异常对象不会在原始抛出代码的堆栈帧中分配,而是以“未指定的方式”分配。


In C++11 the possible ways that exception objects could be allocated (internally in the run time library) was restricted, by the requirement that exception objects could be referenced by essentially shared ownership smart pointers, std::exception_ptr . 在C ++ 11中,可以通过本质上共享的所有权智能指针std::exception_ptr引用异常对象的要求来限制异常对象可以分配的可能方式(在运行时库内部)。

The possibility of shared ownership means that in C++ an exception object can have a guaranteed lifetime beyond the completed handling of the exception. 共享所有权的可能性意味着在C ++中,异常对象可以具有超出完成的异常处理的有保证的生命周期。

This is mainly in support of passing exceptions through non-exception-aware C code, and in order to pass nested exception information. 这主要是为了支持通过非异常感知的C代码传递异常,并且为了传递嵌套的异常信息。

The implementation would vary from platform to platform. 实施因平台而异。 The life cycle is more complicated that one might imagine since the throw statement starts executing in the stack frame of foo(). 生命周期比人们想象的更复杂,因为throw语句开始在foo()的堆栈帧中执行。

It's possible that the exception object gets copies and reallocated, or the catch block might execute in a frame on top of foo but with a pointer to the bar frame in order to reference bar's variables. 异常对象可能会获得副本并重新分配,或者catch块可能在foo顶部的框架中执行,但是带有指向条形框架的指针以引用条形变量。

He, 他,

the line 这条线

 throw(my_exception()) 

generates a new object of the type my_exception. 生成my_exception类型的新对象。 You can specify whatever you want (int, enums, char * or classes). 您可以指定所需的任何内容(int,enums,char *或类)。 Of course, Classes make more sense as you can define additional data to it. 当然,类更有意义,因为您可以为其定义其他数据。

After this, the whole stack will be cleaned up and all recursions are terminated until it gets to the first try/catch block. 在此之后,将清理整个堆栈并终止所有递归,直到它到达第一个try / catch块。 The exception is still alive there. 那个例外仍然存在。 The code in the catch block is just like implementing a if/else block, just a little smarter. catch块中的代码就像实现if / else块一样,只是更聪明一些。

cheers, 干杯,

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM