assert默认仅在Debug模式启用,Release模式通过定义NDEBUG宏禁用;启用需确保未定义NDEBUG(如不加-DNDEBUG),禁用则须在#include前#define NDEBUG或编译时加-DNDEBUG。

assert在C++里怎么启用和禁用
默认情况下,assert 只在 Debug 模式生效;Release 模式下如果没定义 NDEBUG,它仍会编译进去——但多数构建系统(如 CMake 的 Release 配置)会自动加 -DNDEBUG,让 assert 完全消失。这不是“失效”,而是预处理器直接跳过整行。
想手动控制:
- 启用断言:确保编译时没定义
NDEBUG(比如不加-DNDEBUG) - 禁用断言:源码开头写
#define NDEBUG,或编译时加-DNDEBUG - 注意顺序:
#define NDEBUG必须在#include <cassert></cassert>之前,否则无效
assert崩溃时输出的信息从哪来
assert 触发后,标准行为是调用 std::abort(),并打印三样东西:assertion failed、失败的表达式文本、文件名和行号。这些不是运行时解析的,而是靠预处理器宏 __FILE__ 和 __LINE__ 在编译期插进去的。
所以你不能传变量名进去指望它显示值:
立即学习“C++免费学习笔记(深入)”;
int x = -5; assert(x > 0); // 输出的是 "x > 0",不是 "x == -5"
如果要看具体值,得自己拼字符串——但 assert 不支持。这时候该换 static_assert(编译期)或自定义宏(比如用 fprintf + abort)。
assert能用在类成员函数或构造函数里吗
可以,但有隐含风险:如果断言失败,程序直接终止,不会调用栈展开(no stack unwinding),也就不会执行局部对象的析构函数、不会触发 catch 块。
这意味着:
- 在构造函数里用
assert检查参数没问题,但别指望资源自动清理(比如 new 出来的内存不会被 delete) - 在带 RAII 对象的函数里用
assert,那些对象的析构函数不会运行 - 不要在析构函数里用
assert—— C++ 标准明确禁止在~std::uncaught_exceptions()为真时调用std::abort,而析构中抛异常或已处于异常传播路径时,assert可能导致未定义行为
assert和if+throw比有什么实际区别
assert 是开发期诊断工具,if+throw 是运行期错误处理机制,二者定位不同,不该混用。
典型误用:
- 用
assert(ptr != nullptr)替代空指针检查——如果 ptr 来自用户输入或文件,这属于可预期的错误,该用if (!ptr) throw std::invalid_argument("null pointer"); - 在公开 API 函数里放
assert——调用方无法捕获或恢复,且 Release 版本直接删掉,变成静默逻辑漏洞 - 检查 I/O 错误、内存分配失败、系统调用返回值:这些都该用返回值或异常,不是断言场景
真正适合 assert 的,是“这段代码逻辑上绝不该走到这里”或“这个变量在此处必须满足某不变量”,比如循环不变式、算法中间状态、私有辅助函数的前置条件。
最常被忽略的一点:断言表达式本身不能有副作用。写 assert(x++ > 0) 在 Debug 下会自增,在 Release 下不自增——行为不一致,极易引入潜伏 bug。


















