C++primer容器

访问成员函数返回的是引用,front,back,at,和下表,如果一个容器是const,返回的则是const的引用,如果容器不是const,则返回的是普通引用。

是否返回的是引用,关键是看表达式在左值还是在右值,如果在右值,返回的就是元素的一个拷贝,如果在左值,返回的是一个引用对象。

在使用auto的时候,如果想改变该变量的值,要定义成引用类型。

这里指的指针,引用,迭代器实效,说的是可能改变容器的大小。

删除元素的成员函数并不检测其删除参数,在删除元素之前,应该确保它们是存在的。

auto的自动推断类型发生在编译器,因此,auto并不会造成程序运行效率的低下。

在未使用auto的时候,编译器同样需要得知右操作数的类型,然后在与左操作数类型进行比较,检查是否可以发生相应的转化,是否需要进行隐式类型转化。

在使用auto的时候,如果表达式中有引用的含义,则会去除引用的含义,直接对应最原始的数据类型,

auto会去除顶层const,如果auto带上引用,则不会去除const修饰符所带来的作用。

初始值为数组,则使用auto得到的是指针类型,如果带上&,则推导类型为数组类型。

auto并不是一个真正的类型,而是一个占位符,因此不能使用一些以类型为操作数的操作符,如sizeof或者是typeid。

在使用forword_list的时候,需要用到两个迭代器对象,一个是要操作的元素,另外一个是该元素前驱元素。

标准库中的array不支持resize操作,其他的resize操作都是在原来容器的基础之上。

shrink_to_fit仅仅是一个请求,编译器并不一定保证会真正的回退内存空间。

栈默认是基于deque来进行实现的,也可以在list和vector上面实现。

每个适配器都是根据底层来实现自己的操作,不可以直接使用底层操作,这里相当于是对底层操作的一个限制。

queue默认也是基于deque来实现的。

priority_queue是基于vector来实现的。

标准库算法是对迭代器进行操作而不是对容器进行操作,因此,算法并不能直接对容器进行增删

C++中的可调用对象有函数,函数指针,操作符重载,以及使用lambda表达式。

lambda表达式所具有的形式:

[捕获列表](参数列表) -> 返回类型 {函数体}

其中捕获列表是在函数体中定义的局部变量的列表,通常为空,

lambda必须使用尾置返回用来指定其返回类型。

我们可以忽略参数列表和返回类型,但必须永远包括捕获列表和函数体

在lambda表达式中,忽略括号和参数列表等价于定义一个空参数列表,如果忽略返回类型,会自动根据函数体中的代码推断出返回类型。如果函数体中包含return语句,则根据来推断,否则,返回void类型。

lambda表达式不能有默认参数,lambda表达式的实参数目必须和形参数目相同,一旦形参初始化完毕,就可以直行函数体了。lambda就像是一个匿名的内联函数。

捕获列表的存在使得,函数体内可以访问捕获列表中的值。

当定义一个lambda的时候,编译器会生成一个对应新的未命名的类类型,当向一个函数传递lambda的时候,同时定义了一个新类型,和一个该类型的对象,传递的参数就是此编译器生成该类类型的未命名的对象,类似的,当使用auto定义一个用lambda初始化的变量,定义了一个从lambda生成的类型的对象。

默认情况下,由lambda生成的对象,都包含用lambda捕获列表所捕获变量的数据成员,类似于普通函数,lambda的数据成员在lambda对象被创建的时候进行初始化。

被捕获的值是在lambda创建时拷贝,而不是调用时拷贝。

使用bind(functional头文件中)可以,扩展函数调用时候的参数(前提是参数的值是固定的)

bind函数甚至是可以重新安排参数的顺序

对于IO流的对象来讲,只能使用引用类型。

可以通过ref标准库中的函数,返回给定对象的引用,这个对象是可以拷贝的。标准库中有一个cref函数,生成一个保存const引用的类,这两个函数也位于functional头文件中。

容器这一块,需要自己来慢慢参考算法来进行实现

动态内存管理

永远不要用get()方法返回的指针为其他只能指针赋值,这样会导致有多个只能指针指向同一块内存空间,从而使得,任何一个只能指针的引用为0,都会将这块内存空间给释放掉,因此,另外的指针所指向的内存空间也被释放掉了,这就会导致空悬指针。

只能指针的一种类型有,shared_ptr,也是用模板类定义的

智能指针使用的条件限制:

不使用相同的内置指针初始化多个智能指针

不delete get()返回的指针。

不适用get()初始化后者是reset另一个智能指针

如果使用了get()返回的指针,当最后一个智能指针被销毁以后,你的指针就变得无效了。

如果智能指针管理的资源不是new分配的内存,记得传递一个删除器,用来专门释放相应的内存资源。

 由于unique_prt只能指向一个对象,因此,不支持所谓的普通的拷贝和赋值操作。(参数传递的时候的操作是拷贝操作,使用等号时候的操作是赋值操作)

 string::npos

C++中可以使用内置的函数对象,以及自己定义的函数对象。

C++中的vector,采用模板类实现的,实现数据算法,和数据结构的分离.

函数返回值当左值,应该返回的是一个引用。

vector提供了拷贝构造函数,因此可以用另一个vector对象来初始化一个新的vector对象。

list不支持中括号和at操作,不能随机的存取元素。

list的删除操作是左闭右开,是双向列表。

列表插入的位置:链表的节点的index是从0号位置开始的。在3号位置插入元素,是让原来的3号位置变成4号位置,原来的4号位置变成5号位置。删除元素是左闭右开的模式。

优先级队列,创建对象的时候默认是最大值优先队列。

优先队列在queue的头文件下面。

集合set默认情况下是从小到大,统一来进行排序的。

仿函数,less(),greater()是提前定义好的函数对象。仅仅对基础类型进行排序。仿函数是一个类,类中重载了()操作符

放入到容器中的元素必须是可以被拷贝,提供拷贝构造函数,同时重载=运算符。所有容器提供的都是值语义,而非引用语义。

类重载了函数调用操作符,用这样的类定义的对象成为函数对象,用类创建的对象,很像一个函数,成仿函数。

函数对象和普通函数的区别。

函数对象,属于对象,能突破类的概念,保持调用状态。

函数名就是回调函数的入口地址。

函数对象可以记录一些状态信息,

函数对象做函数参数

for_each传递的是值传递,而不是引用传递。

通过for_each的返回值来看调用的次数

STL算法返回的是一个迭代器对象还是一个谓词(函数对象)

函数对象做函数参数或者是函数对象做返回值。

for_each的返回值是一个函数对象

一元谓词,函数参数是一个,函数返回值是bool类型,可以作为一个判断式,谓词可以是一个仿函数,也可以是一个回调函数。

二元谓词,就是有两个参数,返回值是bool类型

函数对象和传统的函数相比,可以做一些保存记录的数据,因此函数对象是封装在类中的,因此可以

find_if算法。

二元函数对象和二元谓词

transform算法

find函数默认是区分大小写的。

functional中定义了很多内置函数对象。

函数适配器,预定义函数对象和其他参数进行绑定。

通过函数对象,实现了算法和数据类型的分类

distance这个函数可以求这个元素的下标位置。

list不是一个随机迭代器,节点的序号是从0号开始,在3号位置插入元素,就是将原来的3号元素,变成4号位置,原来的4号位置变成5号位置。

在3号位置删除元素,就是将原来的4号位置变成3号位置,原来的5号位置变成4号位置,插入和删除是一对互逆的操作。

保证元素可以存在容器中。

list双向列表,不是随机迭代器,可以++可以--但是不能+5或者是-6;

仿函数,谓词,是一个判定式。

容器提供的是值拷贝,不能出现深拷贝和浅拷贝的问题。类需要实现构造函数,拷贝构造函数以及重载等号运算符。

实现了数据类型和算法的分离,自定义函数对象,相当于是仿函数,容器,算法,迭代器的设计理念。

容器提供了统一性,容器和具体的数据类型实现了分离。

算法也提供统一性,通过提供函数对象,相当于是一个回调函数,相当于是函数的调用者和函数的编写者实现了解耦合。

 

posted @ 2017-11-27 17:13  niudong  阅读(173)  评论(0)    收藏  举报