在现代 C++ 中,std::optional(自 C++17 起)为我们提供了一种安全且表达意图清晰的方式来表示函数返回值可能为空或无效的情况。相比传统的指针或特殊值(如 -1、NULL、空字符串等),std::optional 的优势主要体现在以下几个方面:
- 类型安全:
std::optional明确标识该值可能不存在,编译器会在访问前强制检查,减少运行时错误。 - 易读性:函数返回类型直接表明了可空性,调用者一眼即可了解。
- 灵活性:可用于任何可复制或可移动类型,无需特殊的包装或额外类。
下面,我们通过一个完整示例,演示如何在实际项目中使用 std::optional。
1. 基本使用
#include <iostream>
#include <optional>
#include <string>
#include <vector>
std::optional <int> find_in_vector(const std::vector<int>& v, int key) {
for (size_t i = 0; i < v.size(); ++i) {
if (v[i] == key) return static_cast <int>(i); // 找到返回下标
}
return std::nullopt; // 未找到返回 std::nullopt
}
int main() {
std::vector <int> data = {10, 20, 30, 40, 50};
auto pos = find_in_vector(data, 30);
if (pos) { // pos.has_value() 的简写
std::cout << "found at index " << *pos << '\n'; // 取值
} else {
std::cout << "not found\n";
}
}
关键点:
- `std::optional ` 的实例 `opt` 可以使用 `if(opt)` 或 `opt.has_value()` 判断是否包含值。
- 使用解引用
*opt或opt.value()访问值;若为空则抛出std::bad_optional_access。
2. 与异常结合
在某些业务场景下,既需要保留异常信息,又希望返回值可空。我们可以用 std::optional<std::variant<Error, Result>> 组合实现:
#include <variant>
struct Error { std::string msg; };
using Result = int;
std::optional<std::variant<Error, Result>> safe_divide(int a, int b) {
if (b == 0) return std::optional<std::variant<Error, Result>>(Error{"division by zero"});
return Result{a / b};
}
这样调用者可以先判断是否为空,然后再根据内部类型处理错误或成功结果。
3. std::optional 与 std::move
std::optional 本身是一个轻量容器,内部存放类型 T 的实例。对 `std::optional