编译器是否允许优化抛出异常?

时间:2013-10-15 12:23:00

标签: c++ exception compiler-construction compiler-optimization

我们今天在工作中一直在讨论这个话题,我们都没有人能够就这个问题提出明确的答案。请考虑以下情况:

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;
}

现在,目前没有性能问题,所以是的,我们不需要优化甚至关心它。这更像是为了理解允许编译器做什么。

简而言之,它是一种“好”的做法,如果是这样,编译器可以通过不抛出异常来优化它吗? (假设异常构造没有副作用)

2 个答案:

答案 0 :(得分:12)

“编译器是否足够聪明”似乎暗示Exceptions在您的项目中不起作用,如果是这样的话,您不应该首先使用它们(除非您实际上有可能得到例外)。

简答:不,编译器不会根据您使用它们的模式删除异常/异常处理。

当你使用try / catch时,它处理的异常被添加到主异常表中;此表可以被监视,挂钩,添加和删除。仅仅因为你立即发现异常并不意味着其他事情也没有发生。

边来源
Optimizing Away C++ Exception Handling上写了一篇论文,概述了与异常相关的所有(几乎所有)优化的当前实现。在整个过程中,它表明在当前它们不会在编译时被剥离,但会对它们进行优化。本文建议对EH(异常处理)进行增强,以消除不必要的异常,总体而言,这是一个非常好的阅读。

更新(其他来源)
进一步研究该主题,GCC编译器似乎优化掉异常;但是,它确实提供了这样做的选项:-fno-exceptions。此选项将删除所有例外,并直接将其替换为abort()个电话。

另一个来源(here on StackOverflow)没有直接提到“删除异常”,但确实概述了对异常setjmp/longjmp和零成本的两个优化。可以通过突出显示实际增强来推断,而不提及“完全删除异常”,即没有这样的优化(至少对于所提到的编译器而言)。有关这些优化的详细信息的另一个来源可以找到here

答案 1 :(得分:-1)

通过简单的循环可以轻松删除代码中的重复:

int foo()
{
    for (int x : {1, 2, 3, 4})
    {
        int err = some_call(x);
        if (err != 0) return err;
    }
    bar();
    return 0;
}