
int 变量根本不存在“为空”的概念
int 是值类型,不是指针或可空类型,它永远有确定的值——哪怕没显式初始化,在栈上也是未定义值(垃圾值),在全局/静态区则默认为 0。所谓“为空”,其实是误把指针、std::optional 或业务逻辑中的“无效值”混进来了。
常见错误现象:if (x == nullptr) 编译报错;if (!x) 看似能过,但实际是判断是否为 0,不是“空”,容易掩盖真实意图。
- 别用
nullptr、NULL或std::nullopt去比较int - 如果真需要表达“无值”,改用
std::optional<int></int> - 若只是业务上约定某个值代表无效(如 -1、0、INT_MIN),必须在文档或变量名里明确体现,比如
user_id用-1表示未登录,那就写if (user_id == -1)
std::optional 才支持真正的“空值检查”
从 C++17 开始,std::optional 是标准库提供的可空包装器。它把“有值”和“无值”区分得清清楚楚,且不引入额外指针开销。
使用场景:函数返回可能失败(如查找失败)、配置项可能未设置、API 响应字段可选。
立即学习“C++免费学习笔记(深入)”;
- 声明:
std::optional<int> maybe_count;</int>—— 此时就是“空”状态 - 检查是否为空:
if (!maybe_count)或if (maybe_count.has_value()) - 安全取值:
int value = *maybe_count;(仅在确认有值后)或int value = maybe_count.value_or(0); - 注意:
std::optional比int多一个布尔标记位,内存略大,别滥用在高频循环里
用 int* 指针模拟“可空”时的典型陷阱
有人会用 int* 来表示“可能为空”,比如函数返回 int*,nullptr 表示失败。这可行,但风险高。
常见错误现象:解引用前忘了判空,导致段错误;把栈上局部变量地址返回,造成悬垂指针;误以为 int* 和 int 能无缝互换。
- 必须每次解引用前检查:
if (ptr != nullptr) { use(*ptr); } - 别返回局部变量地址:
int* bad() { int x = 42; return &x; }—— 这是未定义行为 - 优先考虑
std::optional或返回std::pair<bool int></bool>,比裸指针更安全、语义更清晰 - 如果必须用指针,确保生命周期管理明确,比如配合
std::unique_ptr或明确所有权契约
零值(0)不等于空,但常被当“默认无效值”用
很多老代码用 0 表示“未设置”或“无效”,比如 id = 0 表示无用户。这本身没问题,但必须全项目统一,并警惕 0 是合法值的场景(如数组索引、计数器归零)。
性能影响几乎为零,但逻辑错误风险极高。
- 避免隐式转换:
if (!id)看似简洁,但掩盖了“0 是业务约定”这一前提,建议写成if (id == 0)并加注释 - 如果 0 是合法值(比如用户 ID 允许为 0),就绝不能用它表示“空”——这时候只能换
std::optional或引入专用哨兵值(如-1) - 数据库映射时尤其注意:SQL 的
NULL对应 C++ 的std::optional,不是0
真正麻烦的从来不是怎么写那行判断,而是搞清你到底想表达“值不存在”,还是“值恰好是 0”,或是“这个变量本不该承担可空语义”。选错类型,后面全是补丁。










