Optional
[TOC]
std::optional
在C++17标准中引入的std::optional是一个模板类,用于表示某个对象的值是可选的,即它可能包含一个值也可能不包含值。std::optional是对在编程中常见的可能不返回值的情况的一种类型安全的替代。
std::optional<T>可以看作一个容器,它最多包含一个类型为T的对象。std::optional主要解决的是某些函数可能不返回结果,或者某些对象在某个时间点可能不持有有效值的问题。
基本用法
使用std::optional非常简单,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <optional>
std::optional<int> GetNumber(bool shouldReturnNumber) {
if (shouldReturnNumber) {
return 42; // 返回一个包含int值的optional
}
return {}; // 返回一个不包含值的optional
}
int main() {
auto number = GetNumber(true);
if (number) { // 检查optional是否包含值
std::cout << "Number is: " << *number << std::endl; // 访问optional中的值
}
auto noNumber = GetNumber(false);
std::cout << "No number value: " << noNumber.value_or(0) << std::endl; // 提供默认值
return 0;
}
使用场景
std::optional的使用场景包括但不限于:
- 函数可能失败,并且没有明显的错误值时(例如,从数据库中查找记录可能找到也可能找不到)。
- 函数可能不返回值,当不想使用异常或者全局变量来报告错误状态。
- 类成员可以在某些时候没有值,
std::optional提供了一种表示和检查这种状态的方法。
使用std::optional比使用指针更安全,因为指针可能为空,这需要手动检查。而std::optional能够明确表示值的存在或缺失,并配备了相应的方法,使代码的意图更明确,也更容易维护。此外,std::optional还有助于避免使用魔法数(比如用-1表示错误或缺失值)来表示缺失值,这样可以减少潜在的bug和误解。
基本函数
-
构造函数:
std::optional可以通过其构造函数来构造,既可以构造出一个空的optional,也可以构造出包含值的optional。1 2 3
std::optional<int> opt1; // 默认构造一个空的optional std::optional<int> opt2 = std::nullopt; // 显式构造一个空的optional std::optional<int> opt3 = 5; // 构造一个包含整数5的optional
-
operator-> 和 operator*: 提供对存储值的访问,如果
std::optional包含一个值。1 2 3
std::optional<std::string> opt("hello"); std::cout << *opt << std::endl; // 使用operator*来解引用 std::cout << opt->size() << std::endl; // 使用operator->访问string的成员函数
-
has_value(): 检查
std::optional是否包含一个值。1 2 3
if (opt.has_value()) { // 或使用 if (opt) std::cout << "opt has a value" << std::endl; }
-
value(): 访问
std::optional中的值,如果std::optional为空,则抛出std::bad_optional_access异常。1 2 3 4 5
try { std::cout << opt.value() << std::endl; } catch (const std::bad_optional_access& e) { std::cout << e.what() << std::endl; }
-
value_or(): 访问
std::optional中的值,如果std::optional为空,则返回一个默认值。1
int value = opt.value_or(0); // 如果opt为空,则返回0
-
reset(): 如果
std::optional中包含值,则销毁该值,使std::optional变为空。1
opt.reset(); // 之后 opt 将不包含值
-
emplace(): 构造
std::optional中的值,原来的值如果存在会被销毁。1
opt.emplace(10); // 在opt中构造一个int值10
使用 std::optional 的正确方式是,在调用 value() 或解引用操作之前,先检查它是否有值,可以使用 has_value() 或者隐式的 bool 转换,这样可以避免潜在的异常或未定义的行为。