C++17新特性optional和string_view
1. optional的作用
类模板 std::optional 管理一个可选的容纳值,即可以存在也可以不存在的值。
一种常见的 optional 使用情况是一个可能失败的函数的返回值。与其他手段,如 std::pair<T,bool> 相比, optional 良好地处理构造开销高昂的对象,并更加可读,因为它显式表达意图。
std::optional对象只是包含对象的内部内存加上一个布尔标志。因此,大小通常比包含的对象大一个字节。对象使用与所包含类型相同的对齐方式。然而,std::optional对象不仅仅是向值成员添加布尔标志功能的结构。例如,如果没有值,就不会为所包含的类型调用构造函数(因此,可以为对象提供没有值的默认状态)。支持Move语义。
2. optional使用
std::optional<>为任意类型的可空实例建模。实例可以是成员、参数或返回值。可以认为std::optional<>是一个包含0或1个元素的容器。
2.1 std::optional<>返回值
/** @file optionalT.cpp
* @note All Right Reserved.
* @brief
* @author xor
* @date 2019-11-2
* @note
* @history
* @warning
*/
#include <iostream>
#include <optional>
#include <string>
// convert string to int if possible:
std::optional<int> asInt(const std::string& s)
{
try
{
return std::stoi(s);
}
catch (...)
{
return std::nullopt;
}
}
std::optional<int> asInt2(const std::string& s)
{
std::optional<int> ret; // initially no value
try
{
ret = std::stoi(s);
}
catch (...)
{
}
return ret;
}
int main()
{
", "hello", "0x33" })
{
// convert s to int and use the result if possible:
std::optional<int> oi = asInt(s);
if (oi) {
std::cout << "convert '" << s << "' to int: " << *oi << "\n";
}
else {
std::cout << "can't convert '" << s << "' to int\n";
}
}
}
has_value()用来检查是否有返回值,如果有通过value()来获取。value()比操作符*更安全,因为没有值而调用该接口的话会抛出异常。操作符*只有你确认有值的情况下才能使用,否则程序会出现未定义行为。
注意,可以通过使用新的类型std::string_view来改进asInt()。
2.2 std::optional<>参数和数据成员
/** @file optionalT.cpp
* @note All Right Reserved.
* @brief
* @author xor
* @date 2019-11-2
* @note
* @history
* @warning
*/
#include <iostream>
#include <string>
#include <optional>
class Name
{
private:
std::string first;
std::optional<std::string> middle;
std::string last;
public:
Name(std::string f,
std::optional<std::string> m,
std::string l)
: first{ std::move(f) }, middle{ std::move(m) }, last{ std::move(l) }
{
}
friend std::ostream& operator << (std::ostream& strm, const Name& n)
{
strm << n.first << ' ';
if (n.middle) {
strm << n.middle.value() << ' ';
}
return strm << n.last;
}
};
int main()
{
Name n{ "Jim", std::nullopt, "Knopf" };
std::cout << n << '\n';
Name m{ "Donald", "Ervin", "Knuth" };
std::cout << m << '\n';
;
}
可选对象还使用<utility>中定义的对象std::in_place(类型为std::in_place_t)来初始化带有多个参数的可选对象的值(参见下面)。
3. optional构造函数
可以创建一个没有值的可选对象。在这种情况下,必须指定包含的类型:
std::optional<int> o1;
std::optional<int> o2(std::nullopt);
这里不会为所包含的类型调用任何构造函数。
可以传递一个值来初始化所包含的类型。根据推导指南,不必指定所包含的类型,如下:
std::optional o3{42}; // deduces optional<int>
std::optional<std::string> o4{"hello"};
std::optional o5{"hello"}; // deduces optional<const char*>
要初始化一个具有多个参数的可选对象,必须创建该对象或将std::in_place添加为第一个参数(所包含的类型无法推断):
std::optional o6{std::complex{3.0, 4.0}};
std::optional<std::complex<double>> o7{std::in_place, 3.0, 4.0};
注意,第二种形式避免创建临时对象。通过使用这种形式,甚至可以传递初始化器列表和附加参数:
// initialize set with lambda as sorting criterion:
auto sc = [] (int x, int y)
{
return std::abs(x) < std::abs(y);
};
std::optional<std::set<int,decltype(sc)>> o8{std::in_place, {4, 8, -7, -2, 0, 5}, sc};
可以复制可选对象(包括类型转换):
std::optional o5{"hello"}; // deduces optional<const char*>
std::optional<std::string> o9{o5}; // OK
还有一个方便的函数make_optional<>(),它允许使用单个或多个参数初始化(不需要in_place参数)。像往常一样make……函数推导:
auto o10 = std::make_optional(3.0); // optional<double>
auto o11 = std::make_optional("hello"); // optional<const char*>
auto o12 = std::make_optional<std::complex<double>>(3.0, 4.0);
然而,注意,没有构造函数接受一个值并根据它的值来决定是使用值初始化一个可选值还是使用nullopt。可以使用操作符?:,例如:
std::multimap<std::string, std::string> englishToGerman;
...
auto pos = englishToGerman.find("wisdom");
auto o13 = pos != englishToGerman.end()? std::optional{pos->second}: std::nullopt;
o13初始化为std::optional<std::string>,这是由于类模板参数的推导std::optionalf(pos->second)。对于std::nullopt类模板参数推导不起作用,但是运算符?:在推导表达式的结果类型时也将其转换为这种类型。
4. string_view
string_view 是C++17所提供的用于处理只读字符串的轻量对象。这里后缀 view 的意思是只读的视图。
- 通过调用 string_view 构造器可将字符串转换为 string_view 对象。
string 可隐式转换为 string_view。 - string_view 是只读的轻量对象,它对所指向的字符串没有所有权。
- string_view通常用于函数参数类型,可用来取代 const char* 和 const string&。
string_view 代替 const string&,可以避免不必要的内存分配。 - string_view的成员函数即对外接口与 string 相类似,但只包含读取字符串内容的部分。
string_view::substr()的返回值类型是string_view,不产生新的字符串,不会进行内存分配。
string::substr()的返回值类型是string,产生新的字符串,会进行内存分配。 - string_view字面量的后缀是 sv。(string字面量的后缀是 s)
5. 示例
/** @file optionalT.cpp
* @note All Right Reserved.
* @brief
* @author xor
* @date 2019-11-2
* @note
* @history
* @warning
*/
#include <string>
#include <functional>
#include <iostream>
//#include <optional>
#include <experimental/optional>//试验阶段
using namespace std;
// optional 可用作可能失败的工厂的返回类型
std::optional<std::string> create(bool b) {
if(b)
return "Godzilla";
else
return {};
}
// 能用 std::nullopt 创建任何(空的) std::optional
auto create2(bool b) {
return b ? std::optional<std::string>{"Godzilla"} : std::nullopt;
}
// std::reference_wrapper 可用于返回引用
auto create_ref(bool b) {
static std::string value = "Godzilla";
return b ? std::optional<std::reference_wrapper<std::string>>{value}
: std::nullopt;
}
int main()
{
std::cout << "create(false) returned "
<< create(false).value_or("empty") << '\n';
// 返回 optional 的工厂函数可用作 while 和 if 的条件
if (auto str = create2(true)) {
std::cout << "create2(true) returned " << *str << '\n';
}
if (auto str = create_ref(true)) {
// 用 get() 访问 reference_wrapper 的值
std::cout << "create_ref(true) returned " << str->get() << '\n';
str->get() = "Mothra";
std::cout << "modifying it changed it to " << str->get() << '\n';
}
}
#include <iostream>
#include <optional>
#include <string_view>
using namespace std;
optional<size_t> find_last(string_view string, char to_find, optional<size_t> start_index = nullopt)
{
if (string.empty())
return nullopt;
size_t index = start_index.value_or();
while (true)
{
if (string[index] == to_find) return index;
) return nullopt;
--index;
}
}
int main()
{
const auto string = "Growing old is mandatory; growing up is optional.";
const optional<size_t> found_a{ find_last(string, 'a') };
if (found_a)
cout << "Found the last a at index " << *found_a << endl;
const auto found_b{ find_last(string, 'b') };
if (found_b)
cout << "Found the last b at index " << found_b.value() << endl;
));
if (found_early_i != nullopt)
cout << "Found an early i at index " << *found_early_i << endl;
}
C++17新特性optional和string_view的更多相关文章
- JDK1.8新特性——Optional类
JDK1.8新特性——Optional类 摘要:本文主要学习了JDK1.8新增加的Optional类. 部分内容来自以下博客: https://www.cnblogs.com/1ning/p/9140 ...
- JAVA8新特性Optional,非空判断
Optional java 的 NPE(Null Pointer Exception)所谓的空指针异常搞的头昏脑涨, 有大佬说过 "防止 NPE,是程序员的基本修养." 但是修养归 ...
- c++17 新特性
编译环境说明:gcc 8.1 + eclipse +windows 10 eclipse cpp默认支持c++14,做c++17开发时,需要手动进行配置. 1.关键字 1)constexpr c++1 ...
- Java 17 新特性:switch的模式匹配(Preview)
还记得Java 16中的instanceof增强吗? 通过下面这个例子再回忆一下: Map<String, Object> data = new HashMap<>(); da ...
- C++17 新特性之 std::optional(上)
最近在学习 c++ 17 的一些新特性,为了加强记忆和理解,把这些内容作为笔记记录下来,有理解不对的地方请指正,欢迎大家留言交流. 引言 在介绍之前,我们从一个问题出发,C++ 的函数如何返回多个值? ...
- Java8 新特性 Optional 类
Optional 类的简介 Optional类的是来自谷歌Guava的启发,然后就加入到Java8新特性中去了.Optional类主要就是为子决解价值亿万的错误,空指针异常. Optional ...
- Java8新特性--Optional
Java 8引入了一个新的Optional类.Optional类的Javadoc描述如下: 这是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会 ...
- Java8新特性——Optional
前言 在开发中,我们常常需要对一个引用进行判空以防止空指针异常的出现.Java8引入了Optional类,为的就是优雅地处理判空等问题.现在也有很多类库在使用Optional封装返回值,比如Sprin ...
- 从Java 9 到 Java 17 新特性梳理
Java 9 新的创建集合的方法 // [1, 2, 3, 4] List<Integer> integers = List.of(1, 2, 3, 4); // {1,2,3} ...
随机推荐
- 【比赛游记】(THUPC,CTS,APIO)2019四连爆蛋记
5 月 11 日 坐飞机来到帝都,报道 THUPC. 试机题有皮配,不会. 晚上吃全聚德,喝星巴克.奢侈. 5 月 12 日 早上打 THUPC. 咕到 9 点半开始,到 2 点半结束.
- opencv想到的
opencv是用C++写的库,包了多种语言接口,包括C,C++,python,java等. OpenCV 是一个开放源代码的计算机视觉库,目前在科研和开发中被广泛使用.OpenCV 由一系列 C 函数 ...
- Linux下用ls和du命令查看文件以及文件夹大小(转)
转自:https://www.cnblogs.com/xueqiuqiu/p/7635722.html ls的用法 ls -l |grep "^-"|wc -l或find ./co ...
- web万维网 -- 基础概念
Web(万维网World Wide Web的简称)是个包罗万象的万花筒,不同的人从不同的角度观察,对于Web究竟是什么会得出大不相同的观点. 百科:web(World Wide Web)即全球广域网, ...
- JavaScript基础12——运动
运动原理 运动的原理: 让某件物品沿着某种方向随着时间的变化改变位置 setInterval(function(){ obox.style.left = obox.offsetLeft+10 ...
- Jupyter的快捷键使用
命令模式 (按键 Esc 开启) Enter : 转入编辑模式 Shift-Enter : 运行本单元,选中下个单元 Ctrl-Enter : 运行本单元 Alt-Enter : 运行本单元,在其下插 ...
- JS继承2
一.原型链继承 关键步骤: 让子类的原型对象成为父类的实例 矫正子类构造器属性 function Animal(name,age){ this.name = name; this.age = age; ...
- transient的
1,transient的用途及使用方法1,用途 我们知道,当一个对象实现了Serilizable接口,这个对象就可以被序列化,我们不关心其内在的原理,只需要了解这个类实现了Serilizable接口, ...
- SpringBoot之AOP使用
说到SpringBoot,难免会想到Spring.对于Spring,我曾用其开发过很多大大小小的项目.当使用SpringBoot之后,给人最直观的感受,用古人一句话:”大道至简”. SpringBoo ...
- 市值TOP10,人类进化及中美坐标
题记:观察人类进化,以及各国.各民族在这个进化中所起的作用.所处的位置,市值 TOP 10 的变迁,会是一个再好不过的指标! 2008年,经历了全球金融危机后,原油期货一路飙升,创出了147.27美元 ...