《C++标准库》学习笔记 — STL — 容器与算法
这里主要学习一些以前没注意的知识点和用的少的算法
一、reverse 迭代器
我们可以将正常迭代器转换为反向迭代器。需要注意的是,转换前后的迭代器逻辑位置发生了变化:
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
vector<int> vec = {
1, 2, 3, 4, 5, 6, 7, 8, 9};
auto iter = find(vec.begin(), vec.end(), 5);
cout << "*iter = " << *iter << endl;
vector<int>::reverse_iterator rIter(iter);
cout << "*reverse iter = " << *rIter << endl;
return 0;
}
这个结果源于区间的半开性。为了指出容器内所有元素,我们需要采用最末元素的下一位置。然而对 reverse 迭代器而言,这个位置位于第一元素之前。糟糕的是,这个为止可能并不存在。为此,reverse 迭代器的设计者运用了一个小技巧:他们实际倒置了半开原则。Reverse 迭代器所定义的区间,并不包括起点,反倒是包括了终点。然而逻辑上其行为一如往常。这么一来 reverse 迭代器物理意义所指的元素位置,和逻辑意义所指的元素位置就不一致。将一个迭代器转换为 reverse 迭代器,其物理位置保持不变。因此,其 value 也就移动到了前一个元素身上。
二、Funtion Object
1、pass by value 的函数对象
需要注意在算法中调用 function object 默认是按值传递:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Sum
{
public:
Sum(int initVal):
sum(initVal)
{
}
operator()(int num)
{
sum += num;
}
int getSum()
{
return sum;
}
private:
int sum;
};
int main(int argc, char* argv[])
{
vector<int> vec;
Sum sum(10);
for (int i = 0;i < 10; i++)
{
vec.push_back(i);
}
for_each(vec.begin(), vec.end(), sum);
cout << sum.getSum() << endl;
return 0;
}
这正是因为值传递无法改变入参的数据。将算法的函数对象设置为值传递是为了让我们可以传入常量表达式暂态表达式(例如lambda表达式);同时,我们也可以改变函数对象的状态或属性。
2、获得结果的办法
如前面的例子,我们希望能够获得最后一次计算后的函数对象引用,以获取 vector 和。为了获得算法的结果或反馈,我们有三种办法:
① 在外部持有数据,函数对象内仅保持引用
② 通过引用传值方式传递函数对象
③ 利用 for_each 算法的返回值
(1)通过引用传值方式传递函数对象
这种方式要求我们在调用算法时,显式地指出模板参数中的函数对象类型为引用:
for_each<vector<int>::iterator, Sum&>(vec.begin(), vec.end(), sum);
(2)利用 for_each 算法的返回值
for_each 算法比较特别,它将函数对象作为结果返回。因此,我们可以这样利用其返回值:
sum = for_each(vec.begin(), vec.end(), sum);
其结果与上面相同。
三、Predicate 和 remove_if
Predicate 就是返回 bool 类型的函数对象。其中的 remove_if 有一些特殊。假如我们想移除指定位置的数据:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
class Nth
{
public:
Nth(int nth):
nth(nth),
count(0)
{
}
bool operator()(int)
{
return ++count == nth;
}
private:
int nth = 0;
int count = 0;
};
int main(int argc, char* argv[])
{
vector<int> vec;
for (int i = 1;i < 10; i++)
{
vec.push_back(i);
}
copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "));
cout << endl;
auto pos = remove_if(vec.begin(), vec.end(), Nth(3));
vec.erase(pos, vec.end());
copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " "));
return 0;
}
这里的结果有点出乎我们意料。该算法不仅仅移除了第3个元素,还移除了第6个元素。这与 remove_if 的实现有关:
template<typename