是否可以有一个零成本assert(),这样代码就不必在调试和发布版本之间进行修改

Is it possible to have a zero-cost assert() such that code should not have to be modified between debug and release builds?

本文关键字:调试 不必 布版本 修改 之间 版本 有一个 零成 是否 assert 代码      更新时间:2023-10-16

我注意到一些代码通常看起来像这样:

#ifdef DEBUG
assert(i == 1);
#endif //DEBUG

并且在您的原始代码中可能有几个这样的块。必须写出每一块是乏味和混乱的。

有这样一个函数可能吗:

auto debug_assert = [](auto expr) { 
#ifdef DEBUG
assert(expr);
#endif //DEBUG
};

或者类似的东西:

#ifdef DEBUG
auto debug_assert = [](bool expr) {
assert(expr);     
};
#else //DEBUG
void debug_assert(bool expr) {}
#endif //DEBUG

在未指定DEBUG标志的情况下获得零成本断言?(也就是说,它应该具有与在没有运行lambda等的情况下没有放入代码相同的效果,并由g++/clang编译器进行优化)。

正如@KerrekSB所提到的,您已经可以通过在包含<cassert>之前定义NDEBUG来禁用断言。确保在包含头文件之前对其进行定义的最佳方法是将其列为编译器的参数(对于gcc,它是-DNDEBUG)

注意:assert是通过将其替换为无运算表达式来删除的,在那里,参数根本不会求值(这与您建议的解决方案不同)!这就是为什么在assert中不调用任何有副作用的函数是至关重要的。

为了完整起见:以下是assert的实现方式:

#include <cstdio>
#include <cstdlib>
#ifndef NDEBUG
#define assert(EXPRESSION) ((EXPRESSION) ? (void)0 : (printf("assertion failed at line %d, file %s: %sn", __LINE__, __FILE__, #EXPRESSION), exit(-1)))
#else
#define assert(EXPRESSION) (void)0
#endif

介绍您自己的assert风格的宏是非常常见的。你可能想这么做有很多原因:

  • 您希望包含有关计算表达式的更多信息(请参阅Catch的REQUIRE,以及他们如何使用表达式模板将表达式分解为各个元素并字符串化)
  • 您想对程序执行除exit()之外的操作,例如抛出异常、向开发人员发送邮件、记录到文件、闯入调试器
  • 即使在发布版本中也要计算表达式,这比根本不计算表达式更不容易出错(毕竟,如果它没有副作用,可以通过编译器优化来消除它,如果它有副作用,你就避免了heisenbug)
  • 等等,等等(如果你有想法,你可以发表评论,我会把它添加到答案中)