C++学习 boost::optional详解 落日映苍穹つ 2022-04-23 12:18 354阅读 0赞 最近接触到boost::optional,网上查了查,这里学习记录一下! # optional: # optional库使用"容器"语义,包装了"可能产生无效值"的对象,实现了"未初始化"的概念. #include <boost/optional.hpp> using namespace boost; # "[无意义][Link 1]"的值: # 函数并不总能返回有效的返回值,很多时候函数可能返回"无意义"的值,这不意味着函数执行失败,而是表明函数正确执行了,但结果却不是有用的值。 表示返回值无意义最常用的做法是增加一个"哨兵"的角色,它位于解空间之外,如NULL,-1,EOF,string::npos,vector::end()等。但这些做法不够通用,而且很多时候不存在解空间之外的"哨兵". optional使用"容器"语义,为这种"无效值"的情形提供了一个较好的解决方案。 **optional很像一个仅能存放一个元素的容器,它实现了"未初始化"的概念:如果元素未初始化,那么容器就是空的,否则,容器内就是有效的,已经初始化的值。** optional的真实接口很复杂,因为它要能够包装任何的类型。 # 操作函数: # optional的模板类型参数T可以使任何类型,就如同一个标准容器对元素的要求,并不需要T具有缺省构造函数,但必须是可拷贝构造的。 可以有很多方式创建optional对象,例如: 【1】**无参的optional()或者optional(boost::none)**构造一个未初始化optional对象,参数**boost::none**是一个类似空指针的none\_t类型常量,表示未初始化; 【2】optional(v)构造一个已初始化的optional对象,其值为v的拷贝。如果模板类型为T&,那么optional内部持有对引用的包装; 【3】optional(condition, v)根据条件condition来构造optional对象,如果条件成立(true)则初始化为v,否则为未初始化; 【4】此外optional还支持拷贝构造和赋值操作,可以从另一个optional对象构造。当想让一个optional对象重新恢复到未初始化状态时,可以向对象赋none值; optional采用了指针语义来访问内部保存的元素,这使得optional未初始化时的行为就像一个空指针。它重载了operator\*和operator->以实现与指针相同的操作,get()和get\_ptr()可以以函数的操作形式获得元素的引用和指针。 成员函数get\_value\_or(default)是一个特别的访问函数,可以保证返回一个有效的值,如果optional已初始化,那么返回内部的元素,否则返回default。 optional也可以用隐式类型转换进行bool测试(用于条件判断),就像一个队指针的判断。 optional还全面支持比较运算,包括==,!=,<,<,>,>=。与普通指针比较的"浅比较"(仅比较指针值)不同,optional的比较是"深比较",同时加入了对未初始化情况的判断。 # 用法: # optional的接口简单明了,把它认为是一个大小为1并且行为类似指针的容器就可以了,或者把它想象成是一个类似scoped\_ptr,shared\_ptr的智能指针(注意,optional不是智能指针,用法类似但用途不同)。 代码示范: \#include <boost/optional.hpp> using namespace boost; using namespace std; int main() \{ optional<int> op0; //一个未初始化的optional对象 optional<int> op1(**boost::none**); //同上,使用none赋予未初始化值 assert(!op0); assert(op0 == op1); assert(op1.get\_value\_or(253) == 253); //获取可选值 optional<string> ops("test"); //初始化为字符串test string str = \*ops; //用解引用操作符获取值 cout <<str.c\_str()<<endl; vector<int> v(10); optional<vector<int>&> opv(v); //容纳一个容器的引用 assert(opv); opv->push\_back(5); //使用箭头操作符操纵容器 assert(opv->size() == 11); ** opv = boost::none;** assert(!opv); system("pause"); return 0; \} 代码示范: \#include <math.h> \#include <boost/optional.hpp> using namespace boost; using namespace std; **optional<double>** calc(int x) //计算倒数 \{ return **optional<double>**(x != 0, 1.0 / x);//条件构造函数 \} optional<double> sqrt\_op(double x) //计算实数的平方根 \{ return optional<double>(x>0, sqrt(x));//条件构造函数 \} int main() \{ optional<double> d = calc(10); if (d) cout << \*d <<endl; d = sqrt\_op(-10); if (!d) cout << "no result"<<endl; system("pause"); return 0; \} # 工厂函数: # optional提供一个类似make\_pair(),make\_shared()的工厂函数**make\_optional(),可以根据参数类型自动推导optional的类型,用来辅助创建optional对象**,声明: optional<T> make_optional(T const &v); optional<T> make_optional(bool condition, T const& v); **但make\_optional()无法推导出T****引用类型****的optional对象,因此如果需要一个optional<****T&****>的对象,就不能使用make\_optional()函数。** 示例; \#include <boost/optional.hpp> \#include <boost/typeof/typeof.hpp> using namespace boost; using namespace std; int main() \{ BOOST\_AUTO(x, **make\_optional(5)**); assert(\*x == 5); BOOST\_AUTO(y, **make\_optional<double>((\*x > 10), 1.0)**); assert(!y); system("pause"); return 0; \} # 高级议题: # optional<T>同STL容器一样,只提供基本的异常保证,不会超过被包装的类型T,它自身不抛出任何异常,只有在T构造时可能会抛出异常。 # 就地创建: # **optional<T>要求类型T具有拷贝语义,因为它内部会保存值的拷贝**,但很多时候复杂对象的拷贝代价很高,而且这个值仅仅作为拷贝的临时用途,是一种浪费。 **因此optional库提供出了"就地创建"的概念,可以不要求类型具有拷贝语义,直接用构造函数所需的参数创建对象,这导致发展处了另一个Boost库--in\_place\_factory**. 示范: \#include <boost/optional.hpp> **\#include <boost/utility/in\_place\_factory.hpp>** using namespace boost; using namespace std; int main() \{ //就地创建string对象,不需要临时对象string("..") optional<string> ops(**in\_place("test in\_place\_factory")**); cout<< (\*ops).c\_str()<<endl; //就地创建std::vector对象,不需要临时对象vector(10, 3) optional<vector<int>> opp(**in\_place(10, 3)**); assert(opp->size() == 10); assert((\*opp)\[0\] == 3); system("pause"); return 0; \} # 引用类型: # optional的模板参数类型可以使引用(T&),它在很多方面与原始类型T有不同,比如无法使用就地创建,就地赋值.与c++语言内置的引用类型不同的是,它可以声明时不指定初值,并且在赋值时转移包装的对象,而不是对原包装的对象赋值。 [Link 1]: https://www.baidu.com/s?wd=%E6%97%A0%E6%84%8F%E4%B9%89&tn=24004469_oem_dg&rsv_dl=gh_pl_sl_csd
相关 C/C++进程超详细详解【中部分】(系统性学习day07) 目录 前言 一、守护进程 1.概念 2.守护进程创建的原理(如图清晰可见) 3.守护进程的实现(代码块) 二、dup和dup2 1,复制文件描述符 2 太过爱你忘了你带给我的痛/ 2024年02月27日 05:43/ 0 赞/ 7 阅读
相关 I2C详解学习 - nRF52832蓝牙芯片 TWI-I2C学习详解笔记 (本文部分来源于网上资源) 1. I2C 总线概述 1.1 主要特征 nRF52832 片内集成了 TWI(Two-wire Serial Interface)两线串 快来打我*/ 2023年07月03日 02:47/ 0 赞/ 92 阅读
相关 C/C++学习 C/C++学习笔记,适用于中、高级。 目录 第一章 类 3 1.1类成员函数 3 1.2解决类成员名和参数名的冲突 3 1.3构造函数和析构函数 3 1.3 £神魔★判官ぃ/ 2022年09月18日 03:49/ 0 赞/ 80 阅读
相关 C#学习之路WindowsMediaPlayer详解 windowsmediaplayer的重要属性如下: 属性/方法名: 说明: \[基本属性\] URL:String; 指定媒体位置,本机或网络地址 uiMod 灰太狼/ 2022年08月07日 09:40/ 0 赞/ 242 阅读
相关 深入学习C语言系列(一):setjmp( )详解 setjmp 与刺激的abort()和exit()相比,goto语句看起来是处理异常的更可行方案。不幸的是,goto是本地的:它只能跳到所在函数内部的标号上,而不 ゝ一纸荒年。/ 2022年07月16日 14:55/ 0 赞/ 98 阅读
相关 C++ 学习笔记:typeid详解 typeid关键字 注意:typeid是操作符,不是函数。这点与sizeof类似) 运行时获知变量类型名称,可以使用 typeid(变量).name() 需要注 不念不忘少年蓝@/ 2022年06月01日 07:23/ 0 赞/ 213 阅读
相关 C++学习_静态成员和const详解 C++学习\_静态成员和const常量 一。static 1. C语言中的static 1). 修饰函数 被修饰的函数只能在当前文件内使用 r囧r小猫/ 2022年05月27日 12:27/ 0 赞/ 162 阅读
相关 C++学习 boost::optional详解 最近接触到boost::optional,网上查了查,这里学习记录一下! optional: optional库使用"容器"语义,包装了"可能产生无效值"的 落日映苍穹つ/ 2022年04月23日 12:18/ 0 赞/ 355 阅读
相关 c\c++中const详解 const修饰一个变量: 在C语言中是一个变量,但具有常属性,不能直接被改变;而c++中是一个常量; const定义常量从汇编的角度来看,只是给出了对应的内存地址 港控/mmm°/ 2022年04月22日 07:44/ 0 赞/ 171 阅读
还没有评论,来说两句吧...