我们今天在工作中一直在讨论这个主题,而我们谁也找不到关于该问题的明确答案。请考虑以下情况:
int foo()
{
int err;
err = some_call(1);
if (err != 0)
return err;
err = some_call(2);
if (err != 0)
return err;
err = some_call(3);
if (err != 0)
return err;
err = some_call(4);
if (err != 0)
return err;
bar();
return err;
}
有很多代码重复。显然,这可以使用宏进行分解,而遗憾的是不能使用模板进行分解(由于return子句)。或至少不是直接。
现在的问题是,如果我们要用异常替换那些返回错误代码,并立即捕获那些异常,编译器是否被允许并且足够聪明以检测模式并避免完全抛出异常?
这是我的意思的说明:
int foo()
{
try
{
// some_call now throws a ErrorReturned exception that contains the error code upon failure.
some_call(1);
some_call(2);
some_call(3);
some_call(4);
}
catch (ErrorReturned& ex)
{
return ex.error_code();
}
bar();
return 0;
}
现在,没有当前的性能问题,所以是的,我们不需要优化甚至不在乎。这更多是为了了解允许编译器执行的操作。
简而言之,这是一种“好的”实践吗?如果是这样,编译器可以通过根本不抛出异常来优化它吗? (假设异常构造没有副作用)
最佳答案
“编译器足够聪明吗”似乎暗示异常在您的项目中没有用,如果是这种情况,则您不应该首先使用它们(除非您实际上有可能获取异常) )。
简短答案:不,编译器不会根据您使用的模式删除您的异常/异常处理。
当您使用try / catch时,它将处理的异常添加到主异常表中。该表可以被监视,挂钩,添加和删除。仅仅因为您立即捕获到异常并不意味着其他事情也不会发生。
辅助来源:
在 Optimizing Away C++ Exception Handling
上写了一篇论文,概述了与异常有关的所有(几乎所有)当前的优化实现。贯穿整个过程,它表明当前在编译时并未剥离它们,而是对其进行了优化。本文本身建议对EH(异常处理)进行增强,以消除不必要的异常,并且总体而言,这是一本不错的文章。
UPDATE (其他来源)
进一步研究该主题,GCC编译器似乎并未优化消除异常;但是,它确实提供了这样做的选项: -fno-exceptions
。此选项将删除所有异常并将其直接替换为abort()
调用。
另一个来源(here on StackOverflow)没有直接提及“删除异常”,但确实概述了对异常所做的两种优化,setjmp/longjmp
和Zero-Cost。可以通过突出显示实际的增强功能来推断出,而没有提到“完全消除异常”,没有这样的优化(但是,至少对于上述编译器而言)。可以找到更多关于这些优化的详细信息的来源here。