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

Why can an anonymous temporary exception be bound to a reference at a catch site?

考虑

#include <iostream>

struct Foo{};

int main(){
    try {
        throw Foo();
    } catch (Foo& e){
        std::cout << "Caught";
    }
}

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

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

The variable declared by the exception-declaration, of type cv T or cv T&, is initialized from the exception object, of type E, as follows:

  • if T is a base class of E, the variable is copy-initialized ([dcl.init]) from an lvalue of type T designating the corresponding base class subobject of the exception object;

  • otherwise, the variable is copy-initialized ([dcl.init]) from an lvalue of type E designating the exception object.

The lifetime of the variable ends when the handler exits, after the destruction of any objects with automatic storage duration initialized within the handler.

I would have thought that the catch should have been const Foo&.

不需要。

我怀疑您期望将左值引用绑定到 non-const。

会出现问题

[except.handle]

The variable declared by the exception-declaration, of type cv T or cv T&, is initialized from the exception object, of type E, as follows:

  • if T is a base class of E ...
  • otherwise, the variable is copy-initialized ([dcl.init]) from an lvalue of type E designating the exception object.

The lifetime of the variable ends when the handler exits, after the destruction of any objects with automatic storage duration initialized within the handler.

注意突出显示的“左值”。将 non-const 左值引用绑定到左值没有问题。


旁注:

A handler is a match for an exception object of type E if

  • The handler is of type cv T or cv T& and E and T are the same type (ignoring the top-level cv-qualifiers), or

顶级 cv 限定符被忽略,不需要匹配抛出的对象和处理程序类型。

... When the handler declares a reference to an object, any changes to the referenced object are changes to the exception object and will have effect should that object be rethrown.

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