assert宏的陷阱与自定义断言设计
请分析 assert() 宏的使用陷阱(如副作用表达式/NDEBUG影响/静态断言区别),并设计一个生产环境可用的自定义断言宏(带日志、断点、不 terminate 的版本)。
回答
Yahuda
assert 陷阱:
- 副作用表达式:
assert(++x < 10)在 NDEBUG 下不执行++x,导致 bug。 - NDEBUG:定义
NDEBUG后 assert 完全消失,依赖 assert 的合法性检查消失。 - 非可流式:不能
assert(x > 0 && "message")之外的复杂信息。 - 与 static_assert 区别:assert 运行时检查,static_assert 编译期检查。
自定义断言:
#include <cstdlib>
#include <iostream>
#define ASSERT(cond, msg) \
do { \
if (!(cond)) { \
std::cerr << "ASSERT: " << #cond << " failed at " \
<< __FILE__ << ":" << __LINE__ << "\n" \
<< "Message: " << msg << "\n"; \
std::abort(); \
} \
} while(0)
生产环境增强版本:
- 支持可选不
abort()的 recoverable assert。 - 写入日志文件而非 stderr。
- 触发 minidump/coredump。
- 条件编译(DEBUG 模式启用,RELEASE 禁用)。
最佳实践:
- 避免在 assert 中使用有副作用的表达式。
- Release 模式使用类似
RELEASE_ASSERT(始终启用但行为不同)。 - 使用
static_assert做编译期检查。