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

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

本文关键字:引用 语法 catch 异常 无意义      更新时间:2023-10-16

我的示例代码:

#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

您通过引用捕获异常对象,但不将其抛出。

异常总是"按值抛出">,因为它们必须分配给进程内存中不受堆栈展开影响的特殊区域。

[C++14: 15.1/3]: 抛出异常副本初始化 (8.5, 12.8( 一个临时对象,称为异常对象。临时值是一个左值,用于初始化在匹配处理程序 (15.3( 中声明的变量。[..]

这是一个一般规则,旨在解释更常见的情况,其中T实际上是try块本身或其封装函数的局部情况。如果不复制它,则不可能从调用范围中捕获它。

我们通过引用捕获异常对象,这样您就不会不必要地再次复制已复制的T。它还会在异常位于继承层次结构中时防止切片。有时人们使用它来改变异常对象,然后再将其重新抛出到调用范围,尽管这似乎

很少见。

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

"> 为什么 T 对象在 catch 块之后仍然打印 100?

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

"> 在这种情况下,引用语法按值传递有什么用?

无。

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

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


顺便说一下,谈到良好做法,使用所有大写名称可能会与宏名称发生冲突,并且(在这种情况下是误导性地(向训练有素的读者指示宏。

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

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


1(曾经,C++98和C++03标准的措辞可以解释为仅通过提及非const保证的效率来捕获。这是一种特殊的解释,但至少有一个著名的C++人士提倡。它现在只是具有历史意义。