【发布时间】:2018-02-19 09:38:15
【问题描述】:
上下文:在这个 answer 中,我了解到 gcc 的 __builtin_unreachable() 可能会产生一些令人惊讶的影响性能影响,如下所示:
if(condition) __builtin_unreachable();
被完全剥离,用作优化提示,只要condition可以保证没有任何副作用。
所以我对此的直接反应是我应该创建以下宏,并在我通常使用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 构建中取消断言。
【问题讨论】:
-
据我所知,没有理由不这样做。您假设在发布版本中进行优化,并在调试版本中用断言替换它以捕获编程错误。
-
“在任何地方都使用它”的方法不会真正起作用,因为调试断言通常包含仅在调试模式下可用的变量和调用。更好的想法是定义一个具有更合适名称的专用宏,例如
my_assume,并仅在适当的地方使用它。 -
一般情况下,可以把东西放在有副作用的断言中,所以我不会这样做。例如,可能有一个昂贵的函数来检查一些不变量:
assert(isStructureValid());。我绝对不想看到在发布版本中调用该函数。因此,正如其他人建议的那样,为此功能创建一个新的assume(或其他名称)宏。或者,使用编译器魔法,如果condition可以在编译时进行评估,则仅在发布版本中应用签入。 -
@geza 将此限制为编译时条件会破坏整个目的(请参阅链接的问题以获取示例)。
标签: c++ gcc optimization assert