value_or()是最安全的std::optional默认值获取方式,不抛异常、语义清晰、支持移动和类型转换,但默认值表达式总会被求值;需延迟计算时可封装value_or_else()。

用 value_or() 最安全地取默认值
当 std::optional 为空时,value_or() 是唯一推荐的“带默认值取值”方式。它不抛异常、不崩溃、语义清晰,且能完美处理移动语义和类型转换。
-
value_or()参数是右值或 const 引用,传入的默认值会被隐式转换为optional的值类型(如果可行) - 若
optional有值,返回其内部值的拷贝(或移动,取决于值类别);若为空,返回你传入的默认值表达式结果 - 注意:默认值表达式**总会被求值**,哪怕
optional非空——这对有副作用的表达式(如函数调用)可能造成意外
std::optional<int> x = std::nullopt;
int v = x.value_or(42); // → 42
<p>std::optional<:string> s = "hello";
auto str = s.value_or("default"); // OK:const char* 转 string
</:string></p></int>
别用 operator* 或 value() 加条件判断来模拟默认值
手写 if (opt.has_value()) return *opt; else return def; 看似可控,实则冗余、易错,且失去 value_or() 对 move-only 类型的天然支持。
-
value()抛std::bad_optional_access异常,不是“获取默认值”的逻辑,而是“断言非空”的信号 -
operator*在空optional上行为未定义,直接崩溃,不能用于兜底 - 手动分支还容易漏掉
const重载或右值场景,比如对std::optional<:vector>>&&移动后取默认值
默认值类型不匹配时编译失败,不是运行时问题
value_or() 要求默认值能隐式转换为目标类型,否则编译报错,错误信息通常指向 value_or 调用处,而非模板深处。
- 例如:
std::optional合法(opt; opt.value_or(5) int→double) - 但
std::optional<:string> opt; opt.value_or(123)编译失败——没有int→std::string隐式构造 - 解决方法:显式构造,如
opt.value_or(std::string{"N/A"})或用花括号初始化(C++17 起支持)
需要延迟计算默认值?自己封装一个 value_or_else()
标准库不提供惰性求值的默认值接口,但你可以轻松补上:
template <typename t typename f>
auto value_or_else(const std::optional<t>& opt, F&& f) {
return opt.has_value() ? *opt : std::forward<f>(f)();
}
</f></t></typename>
- 传入的是可调用对象(lambda、函数指针等),只在
opt为空时才执行 - 适合默认值构造开销大、或有副作用(如日志、计数、网络 fallback)的场景
- 注意:
f返回类型必须能隐式转为T,否则编译失败,和value_or()一致
实际用的时候,90% 场景直接上 value_or() 就行;只有默认值计算昂贵或不允许副作用时,才值得多写两行封装 value_or_else()。别为了“看起来更函数式”而提前抽象。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











