我们今天在工作中一直在讨论这个主题,而我们谁也找不到关于该问题的明确答案。请考虑以下情况:

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

09-09 23:13
查看更多