重读c++Primer 学习笔记 泛型算法篇

标准库容器定义的操作集合惊人的。标准库并未给每个容器添加大量功能,而是提供了一组算法。大多数独立于任何特定的容器。这些算法是通用的(generic,或者泛型的)
大多数算法都在algorithm中,标准库还在numeric中定义了一组数值泛型算法
一般情况下,这些算法不直接操作容器,而是遍历由两个迭代器指定的一个元素范围
迭代器令算法不依赖于容器,但算法依赖于元素类型的操作
泛型算法运行于迭代器之上而不会执行容器操作的特性带来一个令人惊讶但十分必要的编程假定:算法永远不会改变底层容器的大小。算法可能改变元素的值,也可能在容器内移动元素,但永远不会直径添加或删除元素。
标准库提供了超过100个算法。。幸运的是,与容器相似,这些算法有一致的结构。理解结构可以帮助我们更容易地学习和使用算法。
一些算法从两个序列读取数据,一个序列可能是vector,另一个可能是list。而且,容器元素的类型页不要求完全匹配。确保算法不会访问不存在的元素的程序员的责任

c++Primer 第五版 第346页 lambda

到目前为止,我们使用过的仅有的两种可调用对象是函数和函数指针。还有其他两种可调用对象:重载了函数调用运算符的类以及lambda表达式

[capture list](param list) -> return type {function body}
//捕获列表是lambda 所在函数中 定义的局部变量列表
//我们可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体
auto f = []{return 42;};
cout << f() <<endl;//打印42

空捕获列表表明lambda不使用它所在函数中任何局部变量,捕获列表只用于局部非static变量

for_each(wc, words.end(), 
              [](const string &s){cout << s<<" ";});
cout<<endl;

一个lambda可以直接使用定义在当前函数之外的名字。在本例中,cout不是局部名字,而是在头文件iostream中的名字。因此只要作用域包含头文件iostream,我们lambda就可以使用cout。

当定义一个lambda时,编译器生成一个与lambda对应的新的(未命名的)类型。
类似参数传递,变量的捕获方式也可以是值或者引用,采用值捕获的前提是变量可以拷贝。与参数传递不同,变量值在lambda创建时拷贝,而不是调用时拷贝

void fcn1(){
	size_t v1 = 42;
	auto f = [v1] {return v1;};
	v1 = 0;
	auto j = f();// j 为42;f保存了创建时的拷贝
}

void fcn2(){
	size_t v1 = 42;
	auto f2 = [&v1] {return v1;}
	v1 = 0;
	auto j = f2();//j=0
}

除了显式捕获以外,也可以让编译器根据lambda代码来推断我们要使用哪些变量。为了指示推断,我们可以在捕获列表中写一个**&或者=**
如果我们希望一部分值捕获,一部分引用捕获,可以混用隐式和显式捕获。混合使用时,需要先写出=或者&,然后再写显式列表,注意显式和隐式的捕获方式必须不同

void fcn3(){
	size_t v1 = 42;
	auto f = [v1]()mutable{++v1};
	//默认情况下 值拷贝变量不可改变 如果要改变必须加一个mutable在参数列表后面
}

默认情况下,如果一个lambda包含return以外的任何语句,编译器假定其返回void

c++Primer第五版第354页 参数绑定

bind标准库函数 定义在functional头文件中,调用的一般形式为:

auto newCallable = bind(callable, arglist);

当我们调用newCallable 时,他会调用callable,并传递给它arg_list中的参数
arglist的参数可能包含形如_n的名字,其中n是整数。这些参数是“占位符”,表示newCallable的参数
_1表示newCallable的第一个参数,_2表示第二个

auto  check6 = bind(check_size, _1,6);
//check6是一个可调用对象,接受一个string类型参数
//并用这个string和6来调用check_size

bind也可以重新安排其顺序

auto g = bind(f,a,b,_2,c,_1);
//
g(_1,_2)//等价于
f(a,b,_2,c,_1);
c++Primer 第五版 第358页 再谈迭代器

在iterator头文件中,还定义了插入迭代器、流迭代器、反向迭代器、移动迭代器
迭代器类别主要有输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器

  • 大多数算法的形参有如下四种形式:
    • alg(beg, end, other args);
    • alg(beg, end, dest,other args);
    • alg(beg, end,beg2, other args);
    • alg(beg, end, beg2, end2, other args);

算法并不检查,dest假定不管写入多少元素都是安全的
接受单独beg2的算法假定从beg2开始的序列和beg与end之间的空间至少一样大

  • 一些算法使用重载形式传递一个谓词
unique(beg,end);//使用==运算符比较元素
unique(beg,end,comp);//使用comp比较元素
  • if版本的函数
    接受一个元素值的算法通常有另一个不同名(非重载)版本,该版本接受一个谓词代替元素值。接受谓词版本都有_if后缀
find(beg,end, val);//在范围内查找val第一次的位置
find_if(beg, end, pred);//查找第一个令pred为真的元素
  • 区分拷贝元素和不拷贝的版本
    默认情况下,重排元素算法将重排后的元素写会给定的输入序列,这些算法还提供另一个写到指定目的位置的版本。这些算法在名字后附加_copy
reverse(beg, end);
reverse_copy(beg, end, dest);//
//一些算法同时提供_copy 和_if
remove_if(v1.begin(), v1.end(),
       [](int i){return i%2;});
remove_copy_if(v1.begin(), v1.end(),back_inserter(v2),
		[](int i){return i%2;});
  • 特定容器算法
    链表类型list 和forward_list 定义了几个成员函数形式的算法,特别地,他们定义了独有的sort,merge,remove和unique、reverse
list.merge(lst2)
lst.merge(lst2,comp)
将来自lst2的元素合并入lst。元素将从lst2删除。lst和lst2都必须是有序的。第一个版本用<运算符,第二个版本用给定的比较函数
lst.remove(val)
lst.remove_if(pred)
移除掉相等或者满足条件的每个元素
lst.reverse()
lst.sort()
lst.sort(comp)
lst.unique()
lst.unique(pred)

链表还定义了splice算法,属于链表独有,不需要通用版本

lst.splice(args)或flst.splice_after(args)
(p,lst2)p指向lst或flst的首前位置。将lst2所有元素移动到lst中p之前或者flst中p之后,将元素从lst2中删除。lst2必须与lstHuo flst
相同且不能是同一个链表
(p,lst2,p2)将p2指向的元素移动到Lst中或将P2之后的元素移动到flst
(p,lst2,b,e)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值