应使用 std::unreachable()(c++23)或 __builtin_unreachable()(gcc/clang)标记逻辑上绝不会执行的代码,以助编译器优化并避免误报;它不检查条件、无副作用,实际执行则行为未定义。

用 __builtin_unreachable() 告诉编译器“这里绝不会运行”
当逻辑上某段代码绝对不可能被执行(比如 switch 覆盖了所有枚举值后还写了 default),用 __builtin_unreachable() 显式标记,能让编译器彻底删掉后续无用代码、提升优化效果,还能避免误报未初始化警告。
它不是断言,不检查条件;它是给编译器的“指令”,说“执行流到这里就结束了”。GCC 和 Clang 都支持,MSVC 用 __assume(0) 或 C++23 的 std::unreachable()(需 /std:c++23)。
- 只放在确定永不执行的位置,比如
default:分支末尾、if (false)块内、枚举全匹配后的兜底处 - 不能带副作用:调用前不能有未完成的写操作(如
i++)、不能在析构关键资源之后用 - 如果实际运行到这行,行为是未定义的——程序可能直接 abort,也可能跳转乱码,别指望它报错
std::unreachable() 是 C++23 标准方案,但得确认编译器和标准级
这是目前最干净的跨平台写法,语义明确、无需宏或编译器内置函数。但它只在 C++23 及以上生效,且依赖标准库实现是否跟上。
Clang 15+、GCC 13+、MSVC 19.34+(VS 2022 17.4+)已支持,但需显式开启标准:
- Clang/GCC:加
-std=c++23(-std=gnu++23也行) - MSVC:加
/std:c++23,且确保<utility></utility>已包含 - 若用旧标准(如 C++17),
std::unreachable()不可见,会编译失败
示例:
enum class Color { Red, Green, Blue };
void handle(Color c) {
switch (c) {
case Color::Red: return;
case Color::Green: return;
case Color::Blue: return;
default: std::unreachable(); // ✅ C++23 标准写法
}
}
别用 assert(false) 或 throw 替代——目的完全不同
assert(false) 是调试时中止,Release 下被移除,编译器无法据此做优化;throw 引入异常开销,还可能被 catch,完全违背“永不执行”的语义。
常见误用场景:
- 在
default:里写assert(false)→ 编译器仍要生成该分支代码,优化器不敢删 - 为“兜底安全”写
throw std::logic_error("unreachable")→ 即使永不抛出,也要预留异常栈展开逻辑,影响性能和二进制大小 - 把
__builtin_unreachable()放在可能被热补丁或调试器注入的路径上 → 实际可到达,结果 UB
模板元编程或 constexpr if 中,编译期已知不可达时不用手动标记
如果分支在编译期就能确定死路(比如 if constexpr (false) 或特化模板中空实现),编译器自动剔除,加 std::unreachable() 多余,还可能干扰 SFINAE 或概念约束判断。
典型例子:
template<bool b>
constexpr int foo() {
if constexpr (B) {
return 42;
} else {
return 0; // ✅ 这里不需要 std::unreachable()
}
}</bool>
只有当控制流在运行时“逻辑上不可达”,但编译器静态分析无法推断时(比如枚举全枚举但没用 [[fallthrough]] 或属性提示),才需要人工标记。
最容易被忽略的是:标记位置必须紧贴控制流终点,前面不能有变量声明或表达式求值;否则那些代码仍会被编译器视为有效,甚至引发未定义行为。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











