在 catch 块异常中无意义地使用引用传递语法?

Meaningless use of pass by reference syntax in catch block- exception?

我的示例代码:

#include<iostream>
using namespace std;

class Test{ public: int set;};
Test T;

int main()
{
    T.set = 100;
    try{
        throw T;
    }
    catch(Test &T)
    {
        T.set = 0;
    }
    cout<<T.set<<endl;
    return 1;
}

在这里,我通过引用捕获抛出的 T 对象,并在 catch 块中修改它的值。为什么 T 对象在 catch 块之后仍然打印 100?在这种情况下,引用语法比按值传递有什么用?

编译器:gcc 5.1.0

您正在通过引用捕获异常对象,但没有将其抛出。

异常是 总是 "thrown by value",因为它们必须分配在进程内存的一个特殊区域,该区域是免疫的堆栈展开的影响。

[C++14: 15.1/3]: Throwing an exception copy-initializes (8.5, 12.8) a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler (15.3). [..]

这是一条通用规则,旨在解决更常见的情况,在这种情况下,T 实际上是 try 块本身或其封装函数的本地。如果不复制它,就不可能从调用范围中捕获它。

We catch the exception object by reference 这样您就不会不必要地再次 复制 已经复制的 T。当您的异常处于继承层次结构中时,它还可以防止切片。有时人们用它来改变异常对象,然后再将其重新扔给调用范围,尽管这似乎很少见。

通过 reference-to-const 捕获它与通过 reference-to-const 捕获任何其他东西具有相同的好处:它确保您不会改变异常。如果你不重新抛出它,那么这里没有实际好处,但如果像我一样,你默认写 const 作为防止错误的故障保险,没有理由 使用它。

Why does the T object still prints 100 after the catch block?

因为抛出是按值,所以创建了一个副本。

What is the use of reference syntax in this case over pass by value?

没有。

通过参考 const 进行捕获是一个很好的经验法则,因为它通常既高效又安全。

上面的代码,就像我写这篇文章时的代码一样,没有通过引用 const 来理解,所以它只是 (1) 不好的做法。


顺便说一下,使用全大写名称有与宏名称发生冲突的良好做法,并且(在这种情况下误导)向受过训练的人指示宏 reader。

单字母大写名称,特别是 T,在某种程度上是一种特殊情况,因为按照惯例它们被用于模板参数,所以它们不太可能用作宏名称。

不过,我还是推荐旧的约定,宏总是大写,其他任何东西都是混合或小写。


1) 有一次,C++98 和 C++03 标准的措辞可以解释为仅通过引用非 const 保证效率来捕捉。这是一种奇特的解释,但至少被一位著名的 C++ 人士所提倡。现在只是具有历史意义。