为什么匿名临时异常可以绑定到捕获站点处的引用?

P45*_*ent 18 c++ language-lawyer

考虑

#include <iostream>

struct Foo{};

int main(){
    try {
        throw Foo();
    } catch (Foo& e){
        std::cout << "Caught";
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是Caught,但是为什么呢?我本以为catch应该如此const Foo&。我忘记了什么?

eer*_*ika 11

我本以为捕获应该是 const Foo& 。

没必要这样。

我怀疑您期望将左值引用绑定到非常量会出现问题。

[除了句柄]

由异常声明声明的 cv T 或 cv T& 类型的变量是从 E 类型的异常对象初始化的,如下所示:

  • 如果 T 是 E 的基类...
  • 否则,该变量是从指定异常对象的 E 类型左值复制初始化的 ([dcl.init])。

当处理程序退出时,在处理程序中初始化的具有自动存储持续时间的任何对象被销毁后,变量的生命周期结束。

请注意突出显示的“左值”。将非常量左值引用绑定到左值没有问题。


旁注:

处理程序与 E 类型的异常对象匹配,如果

  • 处理程序的类型为 cv T 或 cv T& 并且 E 和 T 为相同类型(忽略顶级 cv 限定符),或者

顶级 cv 限定符将被忽略,并且不需要在抛出的对象和处理程序类型之间进行匹配。

...当处理程序声明对对象的引用时,对引用对象的任何更改都是对异常对象的更改,并且如果重新抛出该对象,则该更改将生效。

捕获引用允许修改异常对象。


Nat*_*ica 10

这是因为抛出的对象被视为左值。 [except.handle]/14状态:

cv T异常声明所声明的类型为或 的变量cv T&是从类型为 的异常对象初始化的E,如下所示:

  • 如果T是 的基类,则该变量是从指定异常对象的相应基类子对象类型E的左值复制初始化的 ([dcl.init]) ;T

  • E否则,该变量是从指定异常对象类型的左值复制初始化的([dcl.init]) 。

当处理程序退出时,在处理程序中初始化的具有自动存储持续时间的任何对象被销毁后,变量的生命周期结束。