guojh's Blog.

C++17相关

字数统计: 1.1k阅读时长: 5 min
2020/05/04

C++17相关

C++17相关内容个人总结,持续更新

一些参考:

optional

  • 模板类,用于表示一个对象可能存在也可能不存在
  • 优点:
    • 显然也可以用一个额外的bool值来表示对象是否存在,但optional可读性
    • 显然也可以用一个pointer表示对象,如果为空指针表示不存在,否则表示对象存在。但这需要动态申请内存,效率上比在栈上分配内存要低很多。虽然定义了operator*() and operator->()操作符,但optional使用栈来管理对象,效率更高
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <string>
#include <fstream>
#include <optional>

using namespace std;

optional<string> readFileAsString(const string &filepath) {
ifstream fin(filepath);

if (!fin) {
fin.close();
return {}; // same as return nullopt;
}

// todo: read file
fin.close();
return "gjgjh";
}

int main() {
optional<string> str = readFileAsString("data.txt");
cout << str.value_or("empty") << endl; // use default value here

// if str has value or not
if (str) { // same as if(str.has_value())
cout << "file read successfully\n";
cout << *str << '\n';
cout << str.value() << endl;
} else {
cout << "file cannot be opened\n";
}

return 0;
}

variant

  • 模板类,用一个变量表示多个类型的数据。类似一个类型安全的union
  • 缺点:variant会重用空间,并没有像struct一样存储每种数据类型的成员。此外,variant还会存储一个隐藏的int,该int标识出它存储的是哪个值。而union只占用最大类型的大小,一般union更省内存。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <variant>
#include <string>
#include <iostream>

using namespace std;

int main() {
variant<int, string> v, w;
v = 12;
int i = get<int>(v);
w = get<int>(v);
w = get<0>(v); // index 0: int, index 1: string
w = v; // same effect as the previous line

// get<double>(v); // error: no double in [int, string]
// std::get<3>(v); // error: valid index values are 0 and 1

// throws on error
try {
std::get<string>(w);
}
catch (const std::bad_variant_access &) {}

// returns null on error
auto *pval = get_if<string>(&v);
if (pval) cout << "variant value: " << *pval << '\n';
else cout << "failed to get value!\n";

// size of variant is bigger than union
cout << "sizeof int: " << sizeof(int) << endl;
cout << "sizeof string: " << sizeof(string) << endl;
cout << "sizeof variant: " << sizeof(v) << endl;

return 0;
}

any

  • 任意类型对象。功能类似variant,但是不建议使用,缺点如下:
    • 容易不经意设置成一些不想要的类型,variant通过模板参数指定类型,不容易出错
    • 对于大类型的对象,动态分配内存,效率低

string_view

  • string的复制、修改等操作会造成拷贝,而string的构造、拷贝会涉及动态内存分配,因此效率一般较低。
  • c风格字符串虽然可以避免字符串的复制,但缺点是不包含size、以及一些常用的字符串函数。
  • string_view不管理内存,只保存一个指向字符串的指针和长度,用于只读字符串,避免了复制操作。同时包含了一些常用的字符串函数。
  • 注意:
    • 以上三种字符串可以相互转换。
    • 对于只读字符串,尽量使用string_view而不是string。
    • 因为string_view并不拷贝内存,所以要特别注意它所指向的字符串的生命周期。string_view指向的字符串,不能再string_view死亡之前被回收(否则会存在悬空指针)。

structured bindings

c++17之前,处理函数多个返回值一般有以下几个方式:

  • 用引用、指针作为函数参数。
  • 返回pair、tuple、vector等。比较简洁,但是读取返回值时,需要x.first、x.second、std::get<1>(x)等,可读性上不高。
  • 返回自定义struct。可读性上,比返回pair和tuple好。缺点是需要定义一个新的类型,代码显得比较冗余。

c++17提出结构化绑定

  • 仍然以pair、tuple、vector等形式返回
  • 具体使用形式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <utility>
#include <tuple>
#include <string>
#include <iostream>

using namespace std;

int main() {
pair<int, string> studentInfo{1, "gjh"}; // also can be tuple or struct
auto[id, name]=studentInfo; // or const auto& [id, name]=studentInfo;
cout << "id: " << id << ", name: " << name << endl;

return 0;
}
CATALOG
  1. 1. C++17相关
    1. 1.1. optional
    2. 1.2. variant
    3. 1.3. any
    4. 1.4. string_view
    5. 1.5. structured bindings