在 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++ 人士所提倡。现在只是具有历史意义。
我的示例代码:
#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++ 人士所提倡。现在只是具有历史意义。