10.2.2 写容器元素的算法
- 我们常常使用back_inserter来创建一个迭代器,作为算法的目的位置来使用
fill_n(back_inserter(vec),10,0);
(每次赋值都会在vec上调用push_back),使用back_inserter按需要增长目标序列
10.2.3 重排容器元素的算法
- 标准库算法对迭代器而不是容器进行操作,因此,算法不能直接添加或删除元素
10.3.1 向算法传递函数
- stable_sort可以维持相等元素的原有顺序
10.3.2 lambda表达式
- lambda必须包含捕获列表和函数体。若有返回类型,必须使用尾置返回。(lambda表达式表示一个可调用的代码单元)
auto f=[]{return 42};
cout<<f()<<endl;//输出42
transform(vi.begin(),vi.end(),vi.begin(),[](itn i)->{if(i<0) return -i;else return i;});
- 一个lambda只有在其捕获列表中捕获一个他所在函数中的局部变量,才能在函数体中使用该变量
- 捕获列表值用于局部非static变量,lambda可以直接使用局部static变量和在他所在函数之外声明的名字
- stable_partition: 在划分后的序列中维持原有元素的顺序
10.3.3 lambda捕获和返回
- 当定义一个lambda时,编译器生成一个与lambda对应的新的未命名的类类型
auto f=[]{return 42;};//定义了一个从lambda生成的类型的对象
- 值捕获:lambda**创建时**拷贝变量,而不是调用时拷贝。
- 当以引用方式捕获一个变量时,必须保证在lambda执行时变量是存在的
- 一般来说,应该疆良减少捕获的数据量,来避免潜在的捕获导致的问题,而且,如果可能的话,应该避免捕获指针或引用
- 可变lambda:默认情况对于一个值被拷贝的变量,lambda不会改变其值。如果我们希望能改变一个呗捕获的变量的值,就必须在参数列表后加上关键字mutable
auto f=[v1]()mutable{return ++v1;};
一个引用捕获的变量是否可以修改依赖于此引用指向的是一个const类型还是一个非const类型 - 默认情况一个lambda体包含任何return之外的任何语句,编译器假定此lambda返回void。
10.3.4 参数绑定
- bind:它接受一个可调用对象,生成一个新的可调用对象来适应源对象的参数列表
auto newCallable=bind(callable,arg_list);
- arg_list中参数包含形如_n是占位符,他们占据了传递给newCallable的参数的位置。例如:_1为newCallable的第一个参数。。。
auto g=bind(f,a,b,_2,c,_1);//传递给g的参数按位置绑定到占位符:当我们调用g时,第一个参数传递给f作为最后一个参数。。
- 默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中。如果我们希望传递给bind一个对象而又不拷贝他,必须使用标准库ref函数
for_each(wors.begin(),words.end(),bind(print,ref(os),_1,' '));
函数ref返回一个对象,包含给定的引用,此对象是可以拷贝的
10.4.1 插入迭代器
inserter(lst3,lst3.begin());
若lst={1,2,3,4},则lst3={1,2,3,4},而front_inserter插入完是4,3,2,1,即后者元素总是插入到容器第一个元素之前,而前者不是,前者总是在指定位置之前插入元素。
10.4.2 iostream迭代器
- istream_iterator读取输入流,ostream_iterator想输出流写数据,这些迭代器将他们对应的流当作一个特定类型的元素序列来处理。
istream_iterator<int> int_in(cin);//从cin读取int
istream_iterator<int> int_eof;//尾后迭代器
ifstream("afile");
istream_iterator<string> str_it(in);//从"afile读取字符串"while(in_iter!=eof)
{
vec.push_back(*in_iter++);//后置递增运算符读取流,返回迭代器的旧值,解引用迭代器,获得从流读取的前一个值
}vector<int> vec(in_iner,eof);//由迭代器范围构造vec
,这个构造函数从cin中读取数据,直至遇到文件尾或者一个不是int的数据为止。读取的数据被用来构造vec。accumulate(initer,eof,0);
ostream_iterator<int> out_iter(cout," ");
for(auto e:vec)
out_iter=e;//*out_iter++=e,赋值时,写操作会被提交
cout<<endl;copy(vec.begin(),vec.end(),out_iter);
10.4.3 反向迭代器
sort(vec.rbegin(),vec.rend());//按逆序排序
反向迭代器从序列尾部开始朝着序列首部移动,++riter使得迭代器在原始序列上从尾到头方向运动rcomma.base();
此函数会返回反向迭代器对应的普通迭代器,rcomma和rcomma.base()必须生成相邻位置而不是相同的位置。- vec.rbegin():指向尾元素的迭代器;vec.rend(): 指向首前元素的迭代器
10.5.1 5类迭代器
- 输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器
10.6 特定容器算法
- 通用版本的sort要求随机访问迭代器,因此不能使用与list和forward_list,因为这两个类型分别提供双向迭代器和前向迭代器。
- 对于链表,应该优先使用成员函数版本的算法而不是通用算法。(通过改变元素间的链接去操作,速度更快)
- 链表特有的操作会改变容器,链表版本会改变底层的容器
小结
- 当我们将一个容器元素类型的值赋予一个插入迭代器时,迭代器会将该值添加到容器中