C++ 是否有任何理由不将assert()封装在一个宏中,该宏在gcc中解析为uu builtin_unreachable()?

C++ 是否有任何理由不将assert()封装在一个宏中,该宏在gcc中解析为uu builtin_unreachable()?,c++,gcc,optimization,assert,C++,Gcc,Optimization,Assert,上下文:在这篇文章中,我了解到gcc的\uuuuu builtin\u unreachable()可能具有一些令人惊讶的影响性能的含义,因为似乎如下所示: if(condition) __builtin_unreachable(); 被完全剥离,并用作优化提示,只要条件可以保证没有任何副作用 因此,我对此的直接反应是,我应该创建以下宏,并在通常使用assert()的任何地方绝对使用它,因为在assert()中产生副作用的代码首先是一个主要错误: // TODO: add handling of

上下文:在这篇文章中,我了解到gcc的
\uuuuu builtin\u unreachable()
可能具有一些令人惊讶的影响性能的含义,因为似乎如下所示:

if(condition) __builtin_unreachable();
被完全剥离,并用作优化提示,只要
条件
可以保证没有任何副作用

因此,我对此的直接反应是,我应该创建以下宏,并在通常使用
assert()
的任何地方绝对使用它,因为在
assert()
中产生副作用的代码首先是一个主要错误:

// TODO: add handling of other compilers as appropriate.
#if defined(__GNUC__) && defined(NDEBUG)
  #define my_assert(condition) \
    if(!(condition)) __builtin_unreachable()
#else 
  #define my_assert(condition) assert(condition)
#endif
从标准的角度来看,这将在普通和
NDEBUG
构建之间创建一个功能分割,您可以通过一个参数将此宏排除在
assert()
的标准行为之外。然而,由于我的代码在断言失败的情况下在功能上是死在水中的,所以从行为的角度来看,它是完全等效的

所以我的问题是:有人能想出一个不这样做的理由吗


在您询问之前,是的,我已经检查过gcc的行为是在
NDEBUG
构建中无效地丢弃断言。

是的,不使用它是有原因的。
有些人使用以下结合了断言和异常(
assert(x>0);if(!(x)的防御代码实践,据我所知,没有理由不这样做。您可以在发布版本中假设一些优化内容,并在调试版本中用断言替换它以捕获编程错误。“在任何地方都绝对使用它”这种方法不会真正起作用,因为调试断言通常包含只有在调试模式下才可用的变量和调用。更好的方法是使用更合适的名称定义一个专用宏,例如
my\u asked
,并仅在适当的位置使用它。一般来说,可以将具有副作用的内容放入断言中,因此我将uld不能这样做。例如,可能有一个昂贵的函数检查一些不变量:
assert(isStructureValid());
。我绝对不希望看到在发布版本中调用该函数。因此,正如其他人建议的那样,创建一个新的
假定
(或其他名称)用于此功能的宏。或者,使用come compiler magic,如果编译时可以计算
条件
,则仅应用签入发布版本。@geza将此限制为编译时条件将无法实现全部目的(请参阅链接问题以获取示例)。我真的不喜欢这种做法,因为它将编程错误和运行时错误混为一谈。在我看来,这种断言没有任何意义。我的代码库不会因此受到影响,但这是一件需要记住的好事情。我看不到这种做法的价值。它似乎违背了
assert()的目的
对发行版代码没有运行时影响。如果您需要,也可以使用异常。这不是防御性的,而是冗余的代码。如果您需要在发行版中进行检查,那么可以创建一个特殊的,甚至在发行版模式下编译的发行版。\u assert,或者只使用异常抛出。assert+throw是不好的做法。@Galik与其说than-idiom是否有价值,不如说than-idiom是否有价值,但事实上,使用我的宏会导致在似乎定义良好的程序中出现UB,这是一个非常有效的观点,并加强了对宏进行适当命名的需要。@Frank:我不同意。如果一个程序不满足断言,那么它就不是一个定义良好的程序。甚至我这个断言不存在,因为它被编译掉了。但是我同意你的观点,应该使用一个不同的命名宏来实现这个目的。