⭐前言与需求
optional: adj.可选择的,选修的
在编程与实际项目中,可能会出现数据不合法的需求与状态。
在以往通常的使用中,通常会为每种数据类型定义一个值作为不合法的标志。比如int = -1
, string = “str_invalid”
等等。
这种方式有许多弊端:
- 编写时麻烦
- 这些不合法数据在有的场景下可能是有效的
- 团队协作时需要来回确认
- 等等
为了处理这种可能出现不合法的情况,C++17推出了std::opational<>
来处理这个问题。
在C++20和C++23对此还进行了加强,但本文不对这些加强做过多演示。
⭐使用
std::optional - cppreference.com
🎛️简单示例
该实例简洁明了,能够基本了解optional的使用大意。
注意在optional是空值时,如还需要取值则会出现异常
terminate called after throwing an instance of ‘std::bad_optional_access’
what(): bad optional access
#include <iostream>
#include <optional>
#include <string>
std::optional<std::string> create_optional(bool flag) {
if (flag) {
return "pass option";
} else {
// {} 也可行
// return {};
return std::nullopt;
}
}
void test(bool flag) {
auto opt = create_optional(flag);
// 可以直接作为if判断
if (opt) {
// 两种取值方法
std::cout << opt.value() << std::endl;
std::cout << *opt << std::endl;
// 可以修改
opt.value() = "modify opt.value()";
std::cout << opt.value_or("no data") << std::endl;
} else {
// terminate called after throwing an instance of
// 'std::bad_optional_access'
// what(): bad optional access
// std::cout << opt.value() << std::endl;
std::cout << opt.value_or("no data") << std::endl;
}
}
int main() {
test(true);
test(false);
}
🎛️构造
🎚️空值
#include <iostream>
#include <optional>
#include <string>
int main() {
std::optional<std::string> op0;
std::optional<std::string> op1 = {};
std::optional<std::string> op2 = std::nullopt;
}
🎚️std::in_place 原位构造
原位构造。使用std::in_place
可以直接使用构造函数了。
#include <iostream>
#include <optional>
#include <string>
int main() {
// 调用 std::string( initializer_list<CharT> ) 构造函数
std::optional<std::string> opt1(std::in_place, {'a', 'b', 'c'});
// 调用 std::string( size_type count, CharT ch ) 构造函数
std::optional<std::string> opt2(std::in_place, 3, 'A');
std::cout << opt1.value() << '\n' << opt2.value() << std::endl;
}
🎚️推导指引
都C++17了,推到指引必不可少
注意数组还是退化成 T*
#include <optional>
#include <string>
int main() {
int arr[2];
// std::optional<int *> opt
std::optional opt{arr};
// class std::optional<const char *>
std::optional str = "abc";
using namespace std::literals;
// class std::optional<std::string>
std::optional str_i = "abc"s;
}
🎚️std::make_optional
用对应的make函数进行构造。
#include <iomanip>
#include <iostream>
#include <optional>
#include <string>
#include <vector>
int main() {
auto opt = std::make_optional<std::vector<int>>(5, 2);
for (int i : *opt) {
std::cout << i << " ";
}
std::cout << std::endl;
std::string str{"hello world"};
auto opts = std::make_optional<std::string>(std::move(str));
std::cout << std::quoted(opts.value_or("empty value")) << std::endl;
std::cout << str << std::endl;
}
🎛️访问
🎚️取值
直接使用operator*()
或者value()
即可
注意,考虑空值时需要套用上带默认值版本的value_or()
#include <iostream>
#include <optional>
#include <string>
int main() {
auto opt = std::make_optional<std::string>("Hello World");
std::cout << opt.value() << std::endl;
std::cout << *opt << std::endl;
std::cout << opt.value_or("no data") << std::endl;
// 都可以修改
// opt.value() = "modify data";
*opt = "modify data";
if (opt.has_value()) {
std::cout << opt.value_or("no data") << std::endl;
}
// 重置
opt.reset();
std::cout << opt.value_or("no data") << std::endl;
// 异常
// terminate called after throwing an instance of 'std::bad_optional_access'
// what(): bad optional access
// std::cout << opt.value() << std::endl;
}
🎚️逻辑判断
因为有operator bool()
所以可以直接在if等逻辑判断中使用。
#include <iostream>
#include <optional>
#include <string>
int main() {
auto opt = std::make_optional<std::string>("Hello World");
if (opt.has_value()) {
std::cout << opt.value_or("no data") << std::endl;
}
if (opt) {
std::cout << opt.value_or("no data") << std::endl;
}
}
⭐END
🌟关注我
关注我,学习更多C/C++,算法,计算机知识
B站:
👨💻主页:天赐细莲 bilibili
![]()