首页 > 解决方案 > 如何在 C++ 中“退出当前函数,如果当前语句出错”

问题描述

我从一个例子开始阐述我的问题。最后以问题的确切陈述结束。

所以在C语言中,我们可以这样写一个宏,

#define NO_ERROR 0
#define RETURN_IF_ERROR(function)                                       \
{                                                                       \
  RetCode = function;                                                   \
  if (RetCode != NO_ERROR)                                              \
  {                                                                     \
      LOG(ERROR,"[%d] line [%d] [%s]", RetCode, __LINE__, __FILE__ ) ); \
      return RetCode;                                                   \
  }                                                                     \
  else {                                                                \
      LOG(VERBOSE,"[%d] line [%d] [%s]", RetCode, __LINE__, __FILE__ ) );\
  }                                                                     \
}

现在这个宏可以用在这样的函数中,

int ConstructAxes() {
    RETURN_IF_ERROR(GetAxis("alpha"));
    RETURN_IF_ERROR(GetAxis("beta"));
    RETURN_IF_ERROR(GetAxis("gamma"));
    RETURN_IF_ERROR(GetAxis("delta"));
    .
    .
    .
}

因此,我们立即退出当前函数(例如 ConstructAxes)并返回错误代码,如果其中调用的函数之一返回错误。如果没有那个宏,对于这 4 个语句中的每一个,我都必须编写一个 if...else 块。我最终会得到 4 行显示实际功能或任务的代码,然后是另外 16 行错误检查(和/或可选的日志记录)。(我见过 700 多行长的函数,只有 20~30 行功能和 600 多行 if...else 错误检查和日志记录。不太容易遵循主要逻辑。)

(在有人指出之前,我不能使用异常。这是一个遗留项目,不使用也不希望使用异常,我也不是编写异常安全代码的专家。同样在有人指出之前,返回的错误代码在更高层次上被重新解释为一些有意义的文本。在哪里以及如何与手头的这个问题无关。)

问题是,宏可能有问题,我更喜欢函数。那么在 C++ 中是否有一些简洁优雅的方法可以在不使用宏的情况下做到这一点?我有一种感觉,这是不可能的。

标签: c++cloggingmacrosruntime-error

解决方案


好的,对于嵌入式设备,您可能需要避免任何可能需要内存分配的复杂 C++ 好东西。但是我会拆分必须始终发生的日志记录部分和块短退出。

  int test_and_log(int RetCode) {
    if (RetCode != NO_ERROR)
      {
          LOG(ERROR,"[%d] line [%d] [%s]", RetCode, __LINE__, __FILE__ ) );
      }
      else {
          LOG(VERBOSE,"[%d] line [%d] [%s]", RetCode, __LINE__, __FILE__ ) );
      }
    return RetCode;
  }

然后是一个极简宏(C方式):

#define RETURN_IF_ERROR(x) { int cr; if ((cr = test_and_log(x)) != NO_ERROR) return cr; }

int ConstructAxes() {
    RETURN_IF_ERROR(GetAxis("beta"));
    RETURN_IF_ERROR(GetAxis("gamma"));
    RETURN_IF_ERROR(GetAxis("delta"));
    .
    .
    .
    return 0;                            // ensure a return value if every line passes
}

但是对于 C++,我仍然会通过抛出一个 int 值来使用极简的异常处理:

  void test_and_log(int RetCode) {
    if (RetCode != NO_ERROR)
      {
          LOG(ERROR,"[%d] line [%d] [%s]", RetCode, __LINE__, __FILE__ ) );
          throw RetCode;
      }
      else {
          LOG(VERBOSE,"[%d] line [%d] [%s]", RetCode, __LINE__, __FILE__ ) );
      }
  }

接着:

int ConstructAxes() {
  try {
    test_and_log(GetAxis("beta"));
    test_and_log(GetAxis("gamma"));
    test_and_log(GetAxis("delta"));
    .
    .
    .
  }
  catch (int RetCode) {
    return RetCode;
  }
  return 0;                            // ensure a return value if every line passes
}

这相当 hacky,因为最佳实践建议只抛出 的子类std::exception以进行一致的异常处理。但是正如您所说,您不想在应用程序中使用异常,这是可以接受的。嵌入式系统的优点是不会构造普通的异常对象。但请不要在普通代码中使用它。


如果你想用内存来换取处理时间,你总是可以test_and_loginline说明符声明......


推荐阅读