std::unreachable 仅在 gcc 13+/clang 14+/msvc 19.35+、-std=c++23 且 -o2+ 优化下触发死代码消除;enum class switch 需穷举所有命名值并配 default 才安全;运行时分支中添加将导致 ub 且不优化。

std::unreachable 什么时候真能删代码
它只在三件事同时满足时才触发死代码消除:GCC 13+ / Clang 14+ / MSVC 19.35+,-std=c++23,且优化等级为 -O2 或更高。低于 -O2(比如 -O1)时 Clang 常忽略;-O0 下多数编译器把它当空语句,但某些配置下反而调用 std::terminate 导致崩溃。
验证是否生效最可靠的方式是加 -O2 -S 生成汇编,搜索对应函数名,看含 std::unreachable() 的分支是否被删除、替换为 ud2(x86)或只剩跳转指令。别靠猜,直接看汇编。
-
#include <utility></utility>必须有,否则编译失败 - 启用 LTO(
-flto)可增强跨函数传播,但需全项目统一开启,否则链接可能失败 - 旧版本(如 GCC 12)可能识别函数签名但不剪枝,此时仍会生成实际调用,不删代码
enum class switch 中怎么写才安全
仅对 enum class + 所有命名值显式列出的 case + default 分支组合有效。编译器依赖枚举的封闭性做静态推导,普通 enum 或 int 不行。
典型正确写法:
enum class Color { Red, Green, Blue };
void handle(Color c) {
switch(c) {
case Color::Red: return;
case Color::Green: return;
case Color::Blue: return;
}
std::unreachable(); // ✅ 编译器能静态证明此处不可达
}
- 新增枚举值后必须同步补
case,否则传入新值会直接 UB(不报错、不崩溃、结果不可预测) -
static_cast<color>(42)</color>这类强制转换绕过类型检查,std::unreachable()无法防御 - 配合
-Wswitch-enum(GCC/Clang)或/we4061(MSVC)强制警告未覆盖项,再加static_assert验证枚举值数量,比单靠std::unreachable()更可靠
哪些地方加了也白加,甚至危险
绝大多数运行时分支里加 std::unreachable() 都不会触发优化,还埋下 UB 隐患。
-
if (x == 2) { std::unreachable(); }——x是变量,编译器无法证明其值范围 -
if (ptr == nullptr) { /* ... */ } else { std::unreachable(); }—— 空指针检查是运行时逻辑,编译器不假设ptr必非空 -
switch(x) { case 0: case 1: default: std::unreachable(); }——x是裸int,编译器无法穷举取值 - 放在虚函数重写末尾、或模板未实例化分支里 —— 控制流图不存在,优化器根本看不到
唯一例外是 if constexpr (false) 分支,这是编译期常量,可被剪枝。
和 assert(false)、__builtin_unreachable 混用会出事
assert(false) 在 NDEBUG 下被移除,而 std::unreachable() 始终存在 —— 两者混用会导致控制流分析断裂,优化器可能误判路径可达性。
__builtin_unreachable() 是 GCC/Clang 扩展,MSVC 不认;std::unreachable() 是标准函数,调试时更可能保留符号信息(GDB 能定位到具体行),模板中还可参与 SFINAE(虽不推荐)。
- 不要写
assert(false); std::unreachable();—— 这是反模式 - 跨平台项目别直接用
__builtin_unreachable(),应封装宏或直接用std::unreachable()并确保构建配置达标 - 它不提供编译期完备性保证:漏写
case不报错,只等运行时 UB
真正难的不是写这一行,而是确保“此处确实永远走不到”这个前提成立——编译器只信你写的控制流图,不替你验证业务逻辑。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











