C++ 顺序容器操作

push_back从顺序容器后添加一个元素(array和forward_list不支持)

注:当我们用一个对象来初始化容器时,或将一个对象插入容器中时,实际上放入到容器中的是一个对象值的拷贝,而不是对象本身。
push_front
除了push_back,list、forward_list和deque容器还支持push_front将元素插入容器头部

deque提供了vector不支持的push_front。
在容器中的特定位置添加元素
insert成员允许我们在容器中任意位置插入元素。vector、deque、list和string都支持insert成员。forward_list提供了特殊版本的insert,我们后面会介绍。
每个insert函数都接受一个迭代器作为其第一个参数,迭代器指出在容器中什么位置放置新元素,它可以指向任何位置甚至容器尾部之后的下一个位置,所以insert函数将元素插入到迭代器所指位置之前,这样我们也能很容易在容器首部插入元素。
在a容器尾部的下一个位置之前插入“123”。
虽然某些容器不支持push_front但是他们对于insert并无类似的限制,因此我们可以用insert在容器首部插入元素。
如果接受一个元素数目和一个值
接受一对迭代器或一个初始化列表的insert将给定范围中的元素插入到指定位置之前

c++11下,接受元素个数或范围insert版本返回指向第一个新加入元素的迭代器。如果范围为空,不插入任何元素insert操作会将第一个参数返回。
insert的返回值
通过使用insert的返回值,可以在容器中一个特定位置反复插入元素

每步while循环会将一个新元素插入到iter之前,并将iter重新改变为lst.begin(),所以我们访问不到那些原先加入的元素。
使用emplace
C++11中含有emplace_front、emplace_back和emplace三个成员,这些操作构造而不是拷贝元素,分别对应push_front、push_back和insert三种操作。
调用push和insert是将元素类型的对象传递给他们,这些对象被拷贝到容器中,而我们调用一个emplace时,是将参数传递给元素类型的构造函数,emplace使用这些参数在容器管理的内存空间中直接构造元素
emplace函数根据元素类型而变化
同时我们传递的参数必须能够和构造函数匹配。
访问元素
包括array在内的每个顺序容器都有一个front成员函数,而除forward_list之外所有顺序容器都包含一个back成员函数,这两个成员分别返回首元素和尾元素的引用

注意:如果c为空,那么以上的操作都将是未定义的。

访问成员函数返回的时引用
在容器中访问元素的成员函数(front、back、下标和at)返回的都是引用,如果容器是一个const,则返回的是const的引用。

下标操作和安全的随机访问
提供快速随机访问的容器(string、vector、deque和array)都提供下标运算符。
如果我们希望下标是合法的,可以使用at成员函数,at成员函数类似下标运算符,但如果下标越界,at会抛出一个out_of_range异常
删除元素

与vector和string不支持push_front一样,这些类型也不支持pop_front,类似的forward_list也不支持pop_back。不能对一个空容器执行弹出操作。
由于他们返回值为void所以如果需要记录弹出的值要提前记录。
从容器内部删除一个元素
erase无论是删除单个元素还是一个范围的元素,返回的都是指向删除的(最后一个)元素之后的位置的迭代器

删除多个元素
特殊的forward_list操作
由于单向链表的特性,为了删去或添加某个元素,我们需要把前驱的元素的链接改为删去元素的后继,但是单向链表没有简单的方法获得一个元素的前驱,所以forward_list是通过改变定义元素之后的元素来完成添加或删除的,这样我们就不用获得前驱了。
由于操作和其他容器上的操作不同,forward_list并没有定义insert、emplace和erase,而是定义了insert_after、emplace_after和erase_after的操作。如果我们要删除第三个元素,那么就要erase_after指向第二个元素的迭代器。
同时forward_list也定义了before_begin,他返回一哥首前迭代器,这个迭代器允许我们在首元素之前那个不存在元素的位置添加或删除元素。


改变容器大小

同理如果保存的是类元素,类元素必须提供默认构造函数。
编写改变容器的循环程序
添加/删除vector、string或deque元素的循环程序必须考虑迭代器、引用和指针可能失效的问题,程序必须保证每个循环步中都更新迭代器、引用或指针。
如果是insert或者erase更新迭代器是比较容易的,因为他们可以返回迭代器

insert和erase都会改变程序的迭代器,所以我们都要重新更新迭代器。
调用erase后我们删去当前偶数元素,并且返回删去元素的后一个元素的迭代器。
调用insert,我们会在当前元素之前插入一个元素,并且返回插入元素的迭代器,由于vector的迭代器支持+=运算,所以我们让迭代器+2,让他置于我们下一个需要检查的数的迭代器。
不要保存end返回的迭代器
当我们添加或删除vector或string的元素后,或在deque中首元素之外任何位置删除或添加元素后,原来的end迭代器都会失效。
如果我们有一个程序想在每个元素后添加一个元素
此代码会无限循环,因为我们insert之后end就失效了,这样我们的begin永远找不到end。
正确的处理是在while的条件中,每次都更新v.end。