第十章 泛型算法
声明: 本文为《C++ Primer 中文版(第五版)》学习笔记。 原书更为详细,本文仅作学习交流使用,未经授权禁止转载。
在公众号【Jacen的技术笔记】,回复 C++,即可获得 两万字C++ Primer 要点整理PDF。
P336-P371
标准库并未给每个容器添加大量功能,而是提供了一组算法。这些算法是通用的,可以用于不同类型的容器和不同类型的元素。
10.1 概述
头文件:algorithm、numeric
算法不依赖于容器,但算法依赖于元素类型的操作。
10.2 初识泛型算法
(1)只读算法
accumulate 求和
equal 是否相等
(2)写容器元素的算法
算法不检查写操作
拷贝算法:copy
重排容器元素的算法:sort
::: tip
标准库函数对迭代器而不是容器进行操作。因此,算法不能直接添加或删除元素
:::
10.3 定制操作
标准库允许我们提供自己定义的操作来代替默认运算符。
(1)向算法传递函数
谓词:
谓词是一个可调用的表达式,其返回结果是一个能用作条件的值。
标准库算法的谓词分为两类:
1、一元谓词:只接受单一参数。
2、二元谓词:接受两个参数。
bool isShorter(const string &s1, const string &s2)
{
retrun s1.size() < s2.size();
}
sort(words.begin(), words.end(), isShorter);
排序算法:
stable_sort算法维持相等元素的原有顺序。
(2)lambda表达式
lamba:
lambda表达式表示一个可调用的代码单元。一个lambda具有一个返回类型、一个参数列表和一个函数体。
[capture list](parameter list) -> return type {function body}
// capture list 捕获列表,lambda所在函数中定义的局部变量
// 捕获列表只用于局部非static变量,lambda可以直接使用局部static变量和在它所在函数之外声明的名字
// lambda必须使用尾置返回来指定返回类型
(3)lambda捕获和返回
两种:值捕获、引用捕获
::: warnning
当以引用方式捕获一个变量时,必须保证在lambda执行时变量是存在的。
一般的,应该尽量减少捕获的数据量,来避免潜在的问题。
如果可能,避免捕获指针或引用。
:::
隐式捕获:
当混合使用隐式捕获和显式捕获时,捕获列表中的第一个元素必须是一个&或=。显式捕获的变量必须使用与隐式捕获不同的方式。
lambda捕获列表 P352
可变lambda:
若希望改变一个被捕获的变量的值,必须在参数列表首加上关键字mutable。
指定lambda返回类型:
当需要为lambda定义返回类型时,必须使用尾置返回类型。
(4)参数绑定
标准库bind函数:
auto newCallable = bind(callable, arg_list);
// 调用newCallable时,newCallable会调用callable,并传递给它arg_list中的参数
10.4 再探迭代器
插入迭代器、流迭代器、反向迭代器、移动迭代器
(1)插入迭代器
back_inserter:创建一个使用push_back的迭代器
front_inserter:创建一个使用push_front的迭代器
inserter:创建一个使用inserter的迭代器
(2)iostream迭代器
istream_iterator 读取输入流
ostream_iterator 向一个输出流写数据
istream_iterator操作:
| istream-iterator操作 | |
|---|---|
| istream_iterator in(is); | in从输入流is读取类型为T的值 |
| istream_iterator end; | 读取类型为T的值得istream_iterator迭代器,表示尾后位置 |
| in1 == in2 in1 != in2 | in1和in2必须读取相同类型。如果它们都是尾后迭代器,或绑定到相同的输入,则两者相等 |
| *in | 返回从流中读取的值 |
| in->mem | 与(*in).mem含义相同 |
| ++in, in++ | 用>>从输入流读取下一个值 |
ostream_iterator操作:
| ostream_iterator操作 | |
|---|---|
| ostream_iterator out(os); | out将类型为T的值写到输出流os中 |
| ostream_iterator out(os, d); | out将类型为T的值写到输出流os中,每个值后面都输出一个d。d指向一个空字符串结尾的字符数组 |
| out = val | 用<<将val写入到out所绑定的ostream中 |
| *out, ++out, out++ |
(3)反向迭代器
反向迭代器就是在容器中从尾元素向首元素反向移动的迭代器。
10.5 泛型算法结构
| 迭代器类别 | |
|---|---|
| 输入迭代器 | 只读、不写;单遍扫描,只能递增 |
| 输出迭代器 | 只写,不读;单遍扫描,只能递增 |
| 前向迭代器 | 可读写;多遍扫描,只能递增 |
| 双向迭代器 | 可读写,多遍扫描,可递增递减 |
| 随机访问迭代器 | 可读写,多遍扫描,支持全部迭代器运算 |
10.6 特定容器算法
对于list、forward_list,应该优先使用成员函数的算法而不是通用算法。
术语
cref标准库函数:返回一个可拷贝的对象,其中保存了一个指向不可拷贝类型的const对象的引用