这些try-catch块的效用和行为有何不同?我什么时候比另一种更喜欢一种形式?
int f() {
try {
...
} catch(...) {
...
}
}
int f() try {
...
} catch (...) {
...
}
答案 0 :(得分:6)
如果整个身体必须进入异常块,我倾向于选择第二种形式,因为它更容易阅读(例如减少一个缩进级别)。
但是,这会产生影响的主要地方是构造函数。考虑:
Foo::Foo ()
try : member_with_throwing_constructor(initial_value)
{
}
catch ( ... )
{
// will process exceptions thrown by `member_with_throwing_constructor`
// this will be added by the compiler if you
// don't finish by a `throw ...` statement.
throw;
}
和
Foo::Foo ()
: member_with_throwing_constructor(initial_value)
{
try
{
}
catch ( ... )
{
// does not catch exceptions thrown in constructor
// of `member_with_throwing_constructor`.
}
// can keep processing if `catch` handler does not `return` or `throw`.
}
这两个代码段的行为完全不同。第一个将捕获数据成员构造函数中引发的异常(通常通过初始化程序列表,但默认构造函数也适用)并将自动重新引发异常,因为无法安全地创建实例。第二种形式不包括数据成员初始化,并允许您选择是否保留对象。
我还想在main()
中添加一个全局try-catch来帮助调试未捕获的异常。以下代码段:
int main ( int, char ** )
try
{
// main program...
}
catch ( const std::exception& error )
{
std::cerr << "Uncaught exception: '" << error << "'." << std::endl;
return (EXIT_FAILURE);
}
catch ( ... )
{
std::cerr << "Uncaught exception of unknown type." << std::endl;
return (EXIT_FAILURE);
}
有些人会争辩说,不捕获异常会导致程序崩溃,您可以获得核心转储来帮助调试。虽然这在调试模式下可能很有用,因为它可以帮助调试器指向引发异常的确切代码行,但我喜欢发送不会崩溃的程序,并且我可以向用户显示一条消息说错误报告已提交。
答案 1 :(得分:2)
函数try-catch块仅在构造函数中有用,即便如此,根本不是很有用。最好忘记它们的存在。