【问题标题】:Lifecycle of thrown exceptions in C++C++中抛出异常的生命周期
【发布时间】:2014-09-19 13:40:37
【问题描述】:

考虑以下简单的 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 程序员,我在这里误解了什么?更准确地说,这些不同的值实际上存在于内存中的什么位置?

【问题讨论】:

  • 例外被特殊处理以允许这样做。我想说你没有误解任何东西,只是你不知道这个特殊规则:)
  • 例外情况是它们是例外。 :) 这意味着编译器和运行时环境会对它们进行特殊处理,以确保它们不会超出范围。
  • 阅读 Scott Meyer 的More Effective C++ - Item 13: Catch exceptions by reference,他在其中讨论了这是如何工作的,以及为什么您应该更喜欢 catch (my_exception &exc) {} 而不是其他形式。跨度>
  • @AlexMDC:假设您正确复制了 Scott 的建议,那是假的。而不是catch (my_exception &exc) {}catch (my_exception const& exc ) {}。更强的保证,更多的约束,更少的出错。

标签: c++ exception-handling


【解决方案1】:

throw-expression 中创建的临时对象用于初始化异常对象本身,该对象(引用标准)“以未指定的方式分配”。该对象(至少)持续到异常被处理,因此处理程序对它的引用在处理程序内有效,或者从处理程序调用的任何函数。

【讨论】:

  • re "那个对象一直持续到异常被处理",它的保证存在可以比这长得多。
  • @Cheersandhth.-Alf:确实,您可以使用exception_ptr 将其生命周期延长到超出处理程序的生命周期。但这超出了这个问题的范围。
  • 也(nit模式),不需要任何“在throw表达式中创建的临时”。您可以通过重写 para 来挽救它。可能。
  • @Cheersandhth.-Alf:是的,我考虑过在复制/移动省略中添加题外话,但我认为最好让答案保持简单并专注于异常对象本身的生命周期问题。
【解决方案2】:

按值抛出异常。

也就是说,指定的对象被复制(可能被切片,就像任何复制初始化一样)或移动。

您可以通过例如引用的异常对象 catch 子句的引用参数,不是在原始抛出代码的堆栈帧中分配的,而是以“一种未指定的方式”分配的。


在 C++11 中,异常对象的可能分配方式(在运行时库内部)受到限制,要求异常对象可以被本质上共享所有权的智能指针 std::exception_ptr 引用。

共享所有权的可能性意味着在 C++ 中,异常对象可以在完成异常处理之后有保证的生命周期。

这主要是为了支持通过non-exception-aware C代码传递异常,并且为了传递嵌套的异常信息。

【讨论】:

    【解决方案3】:

    实现会因平台而异。生命周期比人们想象的要复杂,因为 throw 语句开始在 foo() 的堆栈帧中执行。

    异常对象可能会被复制并重新分配,或者 catch 块可能在 foo 之上的框架中执行,但带有指向 bar 框架的指针以引用 bar 的变量。

    【讨论】:

      【解决方案4】:

      他,

      线

       throw(my_exception()) 
      

      生成 my_exception 类型的新对象。您可以指定任何您想要的内容(int、枚举、char * 或类)。当然,类更有意义,因为您可以为它定义额外的数据。

      在此之后,整个堆栈将被清理,所有递归都将终止,直到它到达第一个 try/catch 块。异常仍然存在。 catch 块中的代码就像实现 if/else 块一样,只是更智能一点。

      干杯,

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-25
        • 1970-01-01
        • 1970-01-01
        • 2018-12-24
        • 2014-07-17
        • 2015-06-25
        • 1970-01-01
        相关资源
        最近更新 更多