是否可以使用零成本assert(),以便不必在调试和发布版本之间修改代码?

Cin*_*lue 0 c++ testing assert

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

#ifdef DEBUG
assert(i == 1);
#endif //DEBUG
Run Code Online (Sandbox Code Playgroud)

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

拥有这样的功能是否合理:

auto debug_assert = [](auto expr) { 
 #ifdef DEBUG
 assert(expr);
 #endif //DEBUG
};
Run Code Online (Sandbox Code Playgroud)

或类似的东西:

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

在未指定DEBUG标志时获得零成本断言?(即它应该具有相同的效果,就好像它没有运行lambda等没有放入代码中那样,并且由g ++/clang编译器优化).

mil*_*bug 6

正如@KerrekSB所提到的,您可以通过NDEBUG在包含之前定义来禁用断言<cassert>.确保在包含头文件之前定义它的最佳方法是将其列为编译器的参数(使用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: %s\n", __LINE__, __FILE__, #EXPRESSION), exit(-1)))
#else
#define assert(EXPRESSION) (void)0
#endif
Run Code Online (Sandbox Code Playgroud)

介绍自己的assert宏是很常见的.您可能有很多理由想要这样做:

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