标准库标头 <optional> (C++17)学习之optional

类模板 std::optional 管理一个可选 的所含值,即既可以存在也可以不存在的值。

一种常见的 optional 使用情况是作为可能失败的函数的返回值。与如 std::pair<T, bool> 等其他手段相比,optional 可以很好地处理构造开销高昂的对象,并更加可读,因为它明确表达了意图。

optional<T> 的任何实例在任意给定时间点要么含值,要么不含值

如果一个 optional<T> 含值,那么保证该值作为 optional 对象所用空间的一部分分配,即不会发生动态内存分配。因此,optional 对象模拟的是对象而非指针,尽管定义了 operator*() 和 operator->() 运算符。

当一个 optional<T> 类型的对象被按语境转换到 bool 时,若对象含值 则转换返回 true,若它不含值" 则返回 false。

optional 对象在下列条件下含值

  • 对象被以 T 类型的值或另一含值 的 optional 初始化/赋值。

对象在下列条件下不含值

  • 对象被默认初始化。
  • 对象被以 std::nullopt_t 类型的值或不含值 的 optional 对象初始化/赋值。
  • 调用了成员函数 reset()。

不存在可选的引用、函数、数组或 cv void:如果以这些类型实例化 optional,那么程序非良构。另外,如果以(可有 cv 限定的)标签类型 std::nullopt_t 或 std::in_place_t 实例化 optional,那么程序非良构。

成员函数

(构造函数)

构造 optional 对象
(公开成员函数)

(析构函数)

销毁容纳的值(如果存在)
(公开成员函数)

operator=

对内容赋值
(公开成员函数)
观察器

operator->operator*

访问所含值
(公开成员函数)

operator boolhas_value

检查对象是否含值
(公开成员函数)

value

返回所含值
(公开成员函数)

value_or

在所含值可用时返回它,否则返回另一个值
(公开成员函数)
修改器

swap

交换内容
(公开成员函数)

reset

销毁任何所含值
(公开成员函数)

emplace

原位构造所含值
(公开成员函数)

非成员函数

make_optional

(C++17)

创建一个 optional 对象
(函数模板)

示例代码:

#include <iostream>
#include <optional>
#include <string>
#include <iomanip>
#include <cstdlib>
#include <vector>#pragma warning(disable:4996)// optional 可用作可能失败的工厂的返回类型
std::optional<std::string> create(bool b)
{if (b)return "Godzilla";return {};
}// 能用 std::nullopt 创建任何(空的)std::optional
auto create2(bool b)
{return b ? std::optional<std::string>{"Godzilla"} : std::nullopt;
}std::optional<const char*> maybe_getenv(const char* n)
{if (const char* x = std::getenv(n))return x;elsereturn {};
}struct A
{std::string s;A(std::string str) : s(std::move(str)) { std::cout << " 已构造\n"; }~A() { std::cout << " 已析构\n"; }A(const A& o) : s(o.s) { std::cout << " 被复制构造\n"; }A(A&& o) : s(std::move(o.s)) { std::cout << " 被移动构造\n"; }A& operator=(const A& other){s = other.s;std::cout << " 被复制赋值\n";return *this;}A& operator=(A&& other){s = std::move(other.s);std::cout << " 被移动赋值\n";return *this;}
};struct B
{std::string s;B(std::string str) : s(std::move(str)), id{ n++ } { note("+ 构造"); }~B() { note("~ 析构"); }B(const B& o) : s(o.s), id{ n++ } { note("+ 复制构造"); }B(B&& o) : s(std::move(o.s)), id{ n++ } { note("+ 移动构造"); }B& operator=(const B& other){s = other.s;note("= 复制赋值");return *this;}B& operator=(B&& other){s = std::move(other.s);note("= 移动赋值");return *this;}inline static int n{};int id{};void note(std::string s) { std::cout << "  " << s << " #" << id << '\n'; }
};int main()
{std::cout << "create(false) 返回 "<< create(false).value_or("empty") << '\n';// 返回 optional 的工厂函数可用作 while 和 if 的条件if (auto str = create2(true))std::cout << "create2(true) 返回 " << *str << '\n';//operator= example std::optional<const char*> s1 = "abcefg", s2; // 构造函数s2 = s1; // 赋值s1 = "hijklm"; // 衰变赋值(U = char[4], T = const char*)std::cout << *s2 << ' ' << *s1 << '\n';//std::optional<T>::operator->, std::optional<T>::operator*  exampleusing namespace std::string_literals;std::optional<int> opt1 = 1;std::cout << "opt1: " << *opt1 << '\n';*opt1 = 2;std::cout << "opt1: " << *opt1 << '\n';std::optional<std::string> opt2 = "abc"s;std::cout << "opt2: " << std::quoted(*opt2) << ", size: " << opt2->size() << '\n';// 你能通过在到 optional 的右值上调用 operator* “取”其所含值auto taken = *std::move(opt2);std::cout << "taken: " << std::quoted(taken) << "\n""opt2: " << std::quoted(*opt2) << ", size: " << opt2->size() << '\n';//std::optional<T>::operator bool, std::optional<T>::has_value examplestd::cout << std::boolalpha;std::optional<int> opt;std::cout << opt.has_value() << '\n';opt = 43;if (opt)std::cout << "设置值为 " << opt.value() << '\n';elsestd::cout << "未设置值\n";opt.reset();if (opt.has_value())std::cout << "值仍被设为 " << opt.value() << '\n';elsestd::cout << "不再设置值\n";//std::optional<T>::value examplestd::optional<int> opt3 = {};try{[[maybe_unused]] int n = opt3.value();}catch (const std::bad_optional_access& e){std::cout << e.what() << '\n';}try{opt3.value() = 42;}catch (const std::bad_optional_access& e){std::cout << e.what() << '\n';}opt3 = 43;std::cout << *opt3 << '\n';opt3.value() = 44;std::cout << opt3.value() << '\n';//std::optional<T>::value_or  examplestd::cout << maybe_getenv("SHELL").value_or("(none)") << '\n';std::cout << maybe_getenv("MYPWD").value_or("(none)") << '\n';//std::optional<T>::swap examplestd::optional<std::string> opt4("First example text");std::optional<std::string> opt5("2nd text");enum Swap { Before, After };auto print_opts = [&](Swap e) {std::cout << (e == Before ? "交换前:\n" : "交换后:\n");std::cout << "opt1 含有 '" << opt4.value_or("") << "'\n";std::cout << "opt2 含有 '" << opt5.value_or("") << "'\n";std::cout << (e == Before ? "---SWAP---\n" : "\n");};print_opts(Before);opt4.swap(opt5);print_opts(After);// 在仅一者含值时交换opt4 = "Lorem ipsum dolor sit amet, consectetur tincidunt.";opt5.reset();print_opts(Before);opt4.swap(opt5);print_opts(After);//std::optional<T>::reset examplestd::cout << "创建空 optional:\n";std::optional<A> opt6;std::cout << "创建并赋值:\n";opt6 = A("Lorem ipsum dolor sit amet, consectetur adipiscing elit nec.");std::cout << "重置 optional:\n";opt6.reset();std::cout << "A示例结束\n";//emaplace examplestd::optional<B> opt7;std::cout << "赋值:\n";opt7 = B("Lorem ipsum dolor sit amet, consectetur adipiscing elit nec.");std::cout << "放置:\n";// 由于 opt 含值,这亦将销毁该值opt7.emplace("Lorem ipsum dolor sit amet, consectetur efficitur. ");std::cout << "B示例结束\n";//std::make_optional exampleauto op8 = std::make_optional<std::vector<char>>({ 'a','b','c' });std::cout << "op1: ";for (char c : op8.value())std::cout << c << ',';auto op9 = std::make_optional<std::vector<int>>(5, 2);std::cout << "\nop2: ";for (int i : *op9)std::cout << i << ',';std::string str{ "hello world" };auto op10 = std::make_optional<std::string>(std::move(str));std::cout << "\nop3: " << quoted(op10.value_or("empty value")) << '\n';std::cout << "str: " << std::quoted(str) << '\n';}

运行结果:

参考:

std::optional - cppreference.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/415903.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ollama拉起本地模型以及rag系统部署。

什么是 Ollama &#xff1f; Ollama 是一个简明易用的本地大模型运行框架。能在本地启动并运行 Llama、qwen、Gemma 及其他大语言模型&#xff0c;没有GPU资源照样可以拉起模型&#xff0c;和LocalAI 比较类似&#xff0c;但是加载模型更容易。 1.安装 安装后运行&#xff0c…

统一NLP和目标检测的DETR(一)——self attention、encoder、decoder

主流目标检测算法劣势 YOLO系列&#xff0c;它基于anchor来做&#xff0c;少不了要用MNS&#xff0c;导致速度相对较慢。 但今天介绍一款DETR&#xff0c;基于VIT的目标检测算法。 那么我们需要先深入过一遍VIT。 Vision transform 1、传统RNN网络的问题 单向&#xff1a;只…

YOLOv8改进实战 | 引入混合局部通道注意力模块MLCA(2023轻量级)

YOLOv8专栏导航:点击此处跳转 前言 YOLOv8 是由 YOLOv5 的发布者 Ultralytics 发布的最新版本的 YOLO。它可用于对象检测、分割、分类任务以及大型数据集的学习,并且可以在包括 CPU 和 GPU 在内的各种硬件上执行。 YOLOv8 是一种尖端的、最先进的 (SOTA) 模型,它建立在以前…

C++和Python混合编程——Python调用C++入门

大纲 背景代码入门环境准备头文件业务代码注册BOOST_PYTHON_MODULE作用 boost::python::class_模板类 编译运行项目地址 背景 Python语言在大数据、人工智能以及大模型开发中扮演着举足轻重的角色&#xff0c;其影响力不断扩大并深化。 在大数据领域&#xff0c;Python以其简…

unittest | 使用unittest模块来测试logging日志模块功能

我们在这篇文章实现了在项目工程中编写一个logging模块&#xff0c;但是我们如何确定我们编写的模块功能的是否正常? 你可能想到将全部代码写完后运行测试&#xff0c;但这是一个非常不好的习惯。❌ 最好的方式&#xff0c;是每写出来一个功能或者方法就对它进行测试&#x…

Java设计模式之装饰器模式详细讲解和案例示范

1. 引言 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许向现有对象添加新的功能&#xff0c;而无需修改其结构。这种模式通过使用组合而非继承来扩展对象的行为&#xff0c;在许多实际应用中极为常见。本文将详细介绍装饰器模式…

使用 docker 部署 kvm 图形化管理工具 WebVirtMgr

文章目录 [toc]前提条件镜像构建启动 webvirtmgr创建其他 superuser配置 nginx 反向代理和域名访问绑定 kvm 宿主机local sockettcp 连接 虚拟机创建创建快照虚拟机克隆删除虚拟机 kvm 官方提供了以下这些图形化管理&#xff0c;license 这块也提示了是商业版&#xff08;Comme…

Android实习面经整理第一篇

蔚来Android实习面经 一面(2024/3/11 35min) 自我介绍聊我的本专业说一说MVP架构,MVVM架构 MVP:V层持有P层,用户点击View,把数据发给P层,P层持有M层,然后P层把V层的数据发给M层获取其他数据,最后M层获取完数据后把数据还给P层,更新V层。P层也有V层的引用。MVVM:V层…

Qt 去掉QDialog对话框的问号

QT 对话框的问号是什么&#xff1f; QDialog默认的window flag中包含了Qt::WindowContextHelpButtonHint,这个flag意思是在窗口上提供“上下文帮助”按钮 使用方式/调用方式 void QWidget::setWhatsThis(const QString &)比如&#xff1a; ui->lineEdit_1->setWh…

【pycharm-乱码】简单记录一下都有哪些涉及编码

控制台 路径&#xff1a;setting-》general-》console setting-》editor-》file encodings 路径&#xff1a;setting-》editor->file and code templates #!/user/bin/env python3 # -*- coding: utf-8 -*-setting->tools->ssh terminal

Conda在线/离线迁移虚拟环境

conda简单使用 1.创建环境&#xff1a; conda create -n myenv python3.82.激活环境 conda activate myenv3.退出环境 conda deactivate4.安装包 pip install xxx5.列出所有环境 conda env list conda info --envs6.删除环境 conda remove -n myenv --all离线迁移conda …

【JavaWeb】JDBCDruidTomcat入门使用

本章使用技术版本&#xff1a; Tomcatv10.1.25 关于javaweb相关的其他技术&#xff0c;比如tomcat和maven&#xff0c;在我的主页记录了笔记&#xff0c;ajax我用的是本地笔记以后再考虑上传&#xff0c;前端三板斧我用的菜鸟教程文档 JDBC 初识 JDBC概念 JDBC 就是使用Jav…

三、建造者模式

构造者模式&#xff08;Builder Pattern&#xff09;使用简单的对象一步一步构建成一个复杂的对象。这种设计模式属于创建者模式&#xff0c;它提供了一种创建对象的最佳方式。一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。例如&#xff0c;计算…

LVDS与SerDes到底是什么关系?

随着智能座舱和智能驾驶功能的应用&#xff0c;汽车中的摄像头和液晶屏越来越多&#xff0c;多种图像显示和多屏互动也成为增强汽车智能化和用户体验的重点内容。 这些图像显示功能需要在不同的控制器之间或者控制器与远端的液晶屏或摄像头之间进行数据传输。 比如中控与仪表之…

AndroidLogger 适配好了,但没法上架

看到有网友还在用之前的 AndroidLogger 版本&#xff0c;让我感动再次花了 2个月适配新的Notepad&#xff0c;总算搞完了&#xff0c;但是Notepad作者反了&#xff0c;我没法上架啊。 演示视频地址&#xff1a; Notepad安卓日志插件&#xff0c;支持文件管理和截屏&#xff0c…

FreeRTOS学习笔记—②RTOS的认识(持续更新中)

由于正在学习韦东山大佬的RTOS课程&#xff0c;结合了网上的一些资料&#xff0c;整理记录了下自己的感悟&#xff0c;用于以后自己的回顾。如有不对的地方请各位大佬纠正。 课程链接&#xff1a;https://www.bilibili.com/video/BV1844y1g7ud/?spm_id_from333.337.search-car…

Elasticsearch 向量数据库本地部署 及操作方法

elasticsearch是个分布式向量数据库&#xff0c;支持多种查找模式。此外还拥有 Metadata、Filtering、Hybrid Search、Delete、Store Documents、Async等能力。本文仅是记录本地测试途中遇到的问题。 一&#xff0c;环境部署 下载软件 首先去官网&#xff0c;选择适合平台下…

GoF 代理模式

代理模式的理解 代理模式&#xff0c;就是自己做不了&#xff0c;需要别人来代理&#xff0c;代替自己来完成。最终这个行为还是要发生&#xff0c;只不过不是由自己来完成&#xff0c;而是由别人代理完成&#xff0c;只是对于客户其他人来说感受不到 代理模式的作用&#xf…

MySQL复习3

视图 视图&#xff08;view&#xff09;是一种虚拟存在的表&#xff0c;是一个逻辑表&#xff0c;本省没有数据&#xff0c;内容由查询定义。 基表&#xff1a;用来创建视图的表叫做基表 通过视图&#xff0c;我们可以查看基表的部分数据。视图数据来自定义视图的查询中使用…

RISC-V (八)定时器中断

​​​​​​​riscv中断的分类 Core local INTerrupt: CLINT CLINT编程接口-寄存器 mtime寄存器&#xff0c;由中断触发的时钟&#xff0c;按照固定频率计数。