c++ optional

news/2024/7/7 18:45:18

std::optional 是在 C++ 17 中引入到标准库中的,C++ 17 之前的版本可以通过 boost::optional 实现几乎相同的功能。

适用场景

需要表示或处理一个“可能为空”的变量,可能是一个为包含任何元素的容器,可能是一个类型的指针没有指向任何有效的对象实例,再或者是一个对象没有被赋予有效的值。通常处理这类问题意味着写更多的代码来处理这些“特殊”情况,很容易导致代码变得冗余,可读性变差或者容易出错。
针对这个问题,有几种方法:

  1. 使用魔术值(magic value)或者空指针(null pointers),如0,-1或者一个最大的非负值(例如std::string::npos)等。魔术值限制了可获得的值得范围,而且对于一些类型,没有明显的魔术值,或者无法用常规手段创建魔术值;用空指针表示没有意义的值意味着其他合法的值必须被分配一个地址空间,这是一个代价高昂的操作并且难以实现。
  2. 如果函数可能出错导致返回结果是无效值,我们会引入boolean或者error code作为函数返回值来表示结果是否有意义。但是这种方法会使函数接口变得隐晦,因为接口的使用者可能并不会检查函数返回值而直接使用结果。
  3. 抛出异常。这样就必须引入try-catch代码块来处理这些异常,使得代码变得冗余,可读性变差。

std::optional为解决这类问题提供了简单的解决方案。optional可以看作是T类型变脸与一个布尔值的打包(wrapper class)。 其中的布尔值用来表示T是否为“空”。

std:optional

std:optional是一个sum type(和类型,例如一个union包含两个类型,一个bool类型和一个uint8_t类型,那么这个union一共会有2+2**8= 258种值,称之为和类型,因为它们的类型数量是用各个类型的类型数量累加求得的。如果换成struct,那么这里的类型数量就是2*2^8=512种),它是类型T 的所有值和一个单独的“什么都没有”的状态的和(它的类型是std::nullopt_t,并且它有一个值std::nullopt)。

简单使用

初始化

// 初始化为空
std::optional<int> emptyInt;
std::optional<double> emptyDouble = std::nullopt;

// 有效值初始化
std::optional<int> intOpt{10};
std::optional intOptDeduced{10.0}; // auto deduced

// 使用make_optional
auto doubleOpt = std::make_optional(10.0);
auto complexOpt = std::make_optional<std::complex<double>>(3.0, 4.0);

// 使用in_place
std::optional<std::complex<double>> complexOpt{std::in_place, 3.0, 4.0};
std::optional<std::vector<int>> vectorOpt{std::in_place, {1, 2, 3}};

// 使用其它optional对象构造
auto optCopied = vectorOpt;

其中,in_place / make_optional来对optional对象进行“原地”构造有几个原因:

  • optional存储的对象需要使用默认构造函数进行构造
  • optional内部存储对象不支持拷贝和移动(non-copyable,non-movable)
  • 提高构造函数有多个参数的类型对象的构造效率

has_value()告诉我们是否有一个值,value()则返回这个值。
如果没有值并且调用了value(),会抛出一个类型为std::bad_optional_access的异常。
可以使用value_or(U&& default)来得到值,如果std::optional为空,则得到default。
reset()清除std::optional包含的对象,让它为空。
类似于std::make_unique和std::make_shared,std::make_optional可以在一个新的std::optional内构造T。

class tStudent
{
public:
	explicit tStudent(std::string str)
	: m_name(str)
	{}
	~tStudent() = default;
}// 构造空的optional
std::optional<tStudent> optStudent;
// 构造名字为“Bob”的tStudent对象存储在optional对象中
optStudent.emplace("Bob");
// 相当于
// optStudent = tStudent{"Bob"};
// "Bob"对象析构,构造"Steve"
optStudent.emplace("Steve")
// "Steve"对象析构
optStudent.reset();
#include <iostream>
#include <optional>

using namespace std;

struct Out {
    string out1;
    string out2;
};

optional<Out> func(const string& in) {
    Out o;
    if (in.size() == 0)
        return nullopt;
    o.out1 = "hello";
    o.out2 = "world";
    return o;
}

int main() {
    if (auto ret = func("hello_world"); ret.has_value()) {
        cout << ret->out1 << endl;
        cout << ret->out2 << endl;
    }
    return 0;
}

http://lihuaxi.xjx100.cn/news/1433793.html

相关文章

SpringBoot 的自动装配特性

1. Spring Boot 的自动装配特性 Spring Boot 的自动装配&#xff08;Auto-Configuration&#xff09;是一种特性&#xff0c;它允许您在应用程序中使用默认配置来自动配置 Spring Framework 的各种功能和组件&#xff0c;从而减少了繁琐的配置工作。通过自动装配&#xff0c;您…

Effective Java笔记(33)优先考虑类型安全的异构容器

泛型最常用于集合&#xff0c;如 Set<E &#xff1e;和 Map<K ,V&#xff1e;&#xff0c;以及单个元素的容器 &#xff0c;如 ThreadLocal<T>和 AtomicReference<T&#xff1e; 。 在所有这些用法中&#xff0c;它都充当被参数化了的容器 。 这样就限制每个容器…

【音视频、chatGpt】h5页面最小化后,再激活后视频停住问题的解决

目录 现象 观察 解决 现象 页面有时候要切换&#xff0c;要最小化&#xff1b;短时间或者几个小时内切换回来&#xff0c;视频可以正常续上&#xff1b;而放置较长时间&#xff0c;几个小时或者一晚上&#xff0c;切换回来后&#xff0c;视频可能卡死 观察 切换页面&#x…

07-2_Qt 5.9 C++开发指南_二进制文件读写(stm和dat格式)

文章目录 1. 实例功能概述2. Qt预定义编码文件的读写2.1 保存为stm文件2.2 stm文件格式2.3 读取stm文件 3. 标准编码文件的读写3.1 保存为dat文件3.2 dat文件格式3.3 读取dat文件 4. 框架及源码4.1 可视化UI设计4.2 mainwindow.cpp 1. 实例功能概述 除了文本文件之外&#xff…

谈谈Spring与字节码生成技术

Java程序员几乎都了解Spring。 它的IoC&#xff08;依赖反转&#xff09;和AOP&#xff08;面向切面编程&#xff09;功能非常强大、易用。而它背后的字节码生成技术&#xff08;在运行时&#xff0c;根据需要修改和生成Java字节码的技术&#xff09;就是一项重要的支撑技术。 …

系列六、Springboot操作RocketMQ

一、同步消息 1.1、发送&接收简单消息 1.1.1、发送简单消息 /*** 测试发送简单消息*/ Test public void sendSimpleMessage() {SendResult result rocketMQTemplate.syncSend("BOOT_TOPIC_SIMPLE", "我是一个简单消息");// 往[BOOT_TOPIC_SIMPLE]主…

【深度学习】再谈向量化

前言 向量化是一种思想&#xff0c;不仅体现在可以将任意实体用向量来表示&#xff0c;更为突出的表现了人工智能的发展脉络。向量的演进过程其实都是人工智能向前发展的时代缩影。 1.为什么人工智能需要向量化 电脑如何理解一门语言&#xff1f;电脑的底层是二进制也就是0和1&…

图解java.util.concurrent并发包源码系列——深入理解ReentrantReadWriteLock读写锁,看完可以吊打面试官

图解java.util.concurrent并发包源码系列——深入理解ReentrantReadWriteLock读写锁&#xff0c;看完可以吊打面试官 ReentrantReadWriteLock的作用ReentrantReadWriteLock的原理ReentrantReadWriteLock源码解析构造方法获取写锁和读锁对象计算读锁被持有数和写锁被持有数的位移…