std::optional 可安全持有无默认构造函数的类型,因其内部仅在有值时才构造T,空状态不调用T的默认构造函数;必须用emplace或std::in_place显式构造,访问前须检查has_value()。

std::optionalemplace 或 std::in_place)。
为什么 std::optional 能装没有默认构造函数的 T
因为 std::optional 内部不调用 T 的默认构造函数——它只在有值时才真正构造 T。空状态下的 std::optional<t></t> 是合法且轻量的,哪怕 T{} 根本编译不过。
常见错误是试图这样写:
class NoDefault {
public:
explicit NoDefault(int x) : val(x) {}
private:
int val;
};
std::optional<nodefault> opt; // ✅ 合法:opt 为空,T 未被构造
std::optional<nodefault> bad = NoDefault(42); // ❌ 编译失败:NoDefault 没有隐式转换构造,且 operator= 不接受右值(除非显式定义)
</nodefault></nodefault>
必须用 emplace 或 std::in_place 构造值
对无默认构造函数的类型,operator= 和直接初始化(如 std::optional<t>{args...}</t>)往往不可用或语义模糊;唯一可靠的方式是 emplace 或带 std::in_place 的构造。
-
opt.emplace(42)—— 最常用,语义清晰,参数完美转发给T的构造函数 -
std::optional<nodefault> opt{std::in_place, 42}</nodefault>—— 等价于 emplace,但用于初始化表达式中 -
opt = NoDefault(42)—— 仅当NoDefault有移动/拷贝构造,且operator=可访问时才可能成功;不推荐依赖
注意:std::in_place 后不能加模板参数(如 std::in_place<nodefault></nodefault>),那是 std::variant 的用法,对 optional 会编译失败。
访问前必须检查 has_value(),否则崩溃
operator*、operator-> 和 value() 在空状态下都会触发未定义行为或抛出 std::bad_optional_access(不是断言,无法忽略)。
正确姿势:
if (opt)
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











