C++异常捕获子句

C++ exceptions catch clause

本文关键字:子句 异常 C++      更新时间:2023-10-16

可能重复:
C++中异常对象的范围

我有以下捕获条款:

catch(Widget w);
catch(Widget& w);
void passAndThrowWidget() {
          Widget localWidget;
      throw localWidget;
}

若我们通过值捕获Widget对象,编译器将进行复制,所以当我们抛出异常时,localWidget超出了范围,我们并没有看到任何问题。

若我们通过引用捕获widget对象,根据引用的概念,"w"指向相同的本地widget,而不是副本。但我看到大多数异常都是由C++中的引用捕获的。我的问题是,当抛出异常并通过引用捕获指向被销毁的对象时,"localWidget"是如何工作的就超出了范围。

谢谢!

throw expr;return expr;的相似之处在于,它使用复制初始化(列表初始化也可以使用C++0x(。但这(主要(是语法。

当涉及到语义时,就像从返回非引用类型的函数返回值一样,抛出也是可以的:

T f()
{
    // t is local but this is clearly fine
    T t;
    return t;
    // and so is this
    throw t;
}

此外,还未指定返回或抛出的内容是returnthrow语句的表达式的结果,还是该表达式的副本(或移动(。

通过引用捕获的通常动机与生存期无关——抛出对象的生存期保证至少与catch子句一样长。它是优选的,因为它允许以多形态设计和使用异常。

C++运行时使用独立于堆栈的内存位置来存储异常对象:

2.4.2分配异常对象

例外情况需要存储抛出。此存储必须持久当堆栈正在展开时,因为它将由处理程序使用,并且必须确保线程安全。异常对象因此,存储通常在堆中分配,尽管实现方式可以提供支撑投掷的应急缓冲装置内存不足时的bad_alloc异常条件(见第3.3.1节(。

(来自安腾C++ABI:异常处理(

因此,当你";引用捕获";是对该内存位置的引用,而不是对已释放堆栈帧的引用。这意味着异常对象可以保证生存足够长的时间,以便异常处理程序使用,即使是通过引用获得的。(不过,一旦你离开catch范围,它们可能会被释放,所以不要抓住异常引用。(

异常是本地作用域规则的异常:

try
{
    Widget w;
    throw w;
}
catch (const Widget& exc)
{
    // exc is a valid reference to the Widget
}

即使本地作用域已经结束,也会以特殊的方式处理异常,因此抛出的内容仍然可以访问。

在这一行中,您正在创建本地对象的副本

throw localWidget;

因此,它不是指您的本地"localWidget"对象,而是该对象的副本(称为exception-object(,它保证在catch子句完全处理异常之前一直有效。

抛出的实例在抛出时被复制。所以你无论如何都会得到一份。

最好通过引用捕获,因为抛出的对象可能是多态的,并且您不希望依赖于多态类的副本生成的"错误代码"。"错误代码"不会特定于在抛出点抛出的派生类。