在日常写 C++ 项目的时候,你是不是经常遇到这样的场景:
👉 写了一个函数,它可能有返回值,也可能没找到结果,于是你返回 -1、nullptr、或者干脆塞个布尔值配合输出参数。
这些“土办法”虽然能用,但总感觉怪怪的。
比如返回 -1 表示没找到,别人读代码时完全要靠注释或者经验才知道这个含义。
C++17 为我们带来了一个更优雅的工具 —— std::optional,它可以帮你自然地表达“这个值可能存在,也可能不存在”的语义。
今天咱们就来聊聊它的用法和应用场景。🚀
🔧基础概念与操作
std::optional<T> 可以看作是一个“盒子”,里面要么装着一个 T 类型的值,要么是空的。
引入头文件:
#include <optional>
✅ 创建与赋值
std::optional<int> a; // 空
std::optional<int> result = 10; // 有值
result = 20; // 重新赋值
result.reset(); // 清空
🔍 判断是否有值:
if (result.has_value()) {
// 有值,可以使用
}
也可以直接写:
if (result) {
// 有值
}
🔓 解包取值:
std::optional<int> opt = 10;
int value = *opt; // 直接解包,不建议这样做,可能抛异常
int value = opt.value_or(0); // 推荐带默认值访问, opt为空时返回0
是不是感觉用起来很直观?不用再纠结什么魔法数字、nullptr 了。😉
应用场景举例 🎯
1. 表示“可能失败”的返回值
最常见的用法就是替代“特殊值”来表示失败。
std::optional<int> FindIndex(const std::vector<int>& vec, int target) {
for (size_t i = 0; i < vec.size(); ++i) {
if (vec[i] == target) {
return static_cast<int>(i);
}
}
return std::nullopt; // 没找到
}
调用方就可以清晰地判断:
auto idx = FindIndex({1,2,3}, 2);
if (idx) {
std::cout << "Found at " << *idx << "\n";
} else {
std::cout << "Not found\n";
}
相比返回 -1,是不是更清楚明白?✨
2. 替代 “bool + 输出参数”
很多 C 风格的 API 都是这样设计的:
bool GetResult(int& out_val);
调用的时候需要先准备一个变量,成功时才会被赋值,看起来就很别扭。
用 std::optional,我们可以更自然地表达:
std::optional<int> GetResult() {
if (/*成功*/) {
return 42;
}
return std::nullopt;
}
auto r = GetResult();
if (r) {
std::cout << "Result: " << *r << "\n";
} else {
std::cout << "No result" << "\n";
}
这样函数就变得更加简洁,不再需要额外的输出参数。🌟
3. 作为函数参数表示“可选参数”
有时候我们写函数,希望某个参数是可选的。以前可能用默认值 "" 或者 -1 来凑合。
void PrintMessage(std::string msg, std::optional<std::string> prefix = std::nullopt) {
if (prefix) {
std::cout << *prefix << ": ";
}
std::cout << msg << "\n";
}
PrintMessage("Hello");
PrintMessage("World", "Debug");
这样表达就更符合直觉了:要么传一个值,要么就完全不传。👐
小结 🍵
std::optional 是 C++17 带来的一个小而美的工具,它的核心作用就是:
👉 让“值存在 / 不存在”的语义更加清晰,避免使用 -1、nullptr 等模糊的占位符。
虽然只是个“小语法糖”,但它能让代码的可读性和健壮性都提升不少。
下次写接口的时候,不妨试试把 std::optional 用起来,相信你会喜欢上它的。😎
本文首发于微信公众号《Linux在秋名山》,欢迎大家关注~

252

被折叠的 条评论
为什么被折叠?



