9.3 顺序容器操作


顺序容器和关联容器的不同之处在于两者组织元素的方式。这些不同之处直接关系到了元素如何存储、访问、添加以及删除。

向顺序容器添加元素

  1. 适合除array外顺序容器。
  2. 对vector、string和deque在尾部外的位置添加元素,会导致元素移动。有可能导致对象存储空间的重新分配。
  3. 向容器中插入元素会使指向容器的迭代器、引用和指针失效。
  4. 当我们用一个对象来初始化容器时,或将一个对象插入到容器中时,实际上放入到容器中的是对象值的一个拷贝,而不是对象本身。容器中的元素与提供值的对象之间没有任何关联。随后对容器中元素的任何改变都不会影响到原始对象,反之亦然。
  5. 将元素插入到vector、deque和string中的任何位置都是合法的。然而,这样做可能很耗时。
//容器尾添加元素:vector、string、deque支持
c.push_back(t);
c.emplace_back(t);

//容器首添加元素:forward_list、list、deque支持,string支持push_back
c.push_front(t);
c.emplace_front(t);

//特定位置添加元素:list、vector、string、deque。
//forward_list提供了特殊版本的insert
//插入位置是指定位置之前。比如指定n.begin(),则插在最开头。具体理解就是将后续决定的元素插入到p迭代器之前一位。
//insert返回指向第一个新加入元素的迭代器,若容器为空返回p迭代器
//forward_list有其特殊的insert,后面再介绍
c.insert(p,t) //插入单个,p为迭代器
c.emplace(p,t)
c.insert(p,n,t)//插入多个,n为数目
c.insert(p,b,e)//p为插入目标迭代器,be为参考对象迭代器
c.insert(p,il)//i1为初始化列表

emplace与insert

emplace将参数传递给元素类型的构造函数,直接在容器中构造元素,传递给empalce函数的参数必须与元素类型的构造函数相匹配。
调用push_back或insert,会创建一个局部临时对象,压入容器后再删除。

访问元素

切勿访问一个空容器的元素,因为这样的行为造成的结果是未定义的。

在顺序容器中访问元素的操作说明
c.back()返回c中尾元素的引用,不支持forward_list。
c.front()返回c中首元素的引用
c[n]返回下标为n的元素的引用,n是一个无符号整数,如果n>=c.size(),则此行为未定义,不支持forward_list和list
c.at(n)返回下标为n的元素的引用,如果下标越界,则发出out_of_range的异常,不支持forward_list和list

值得注意的是:

  1. 访问成员函数返回的是引用,如果容器是常量容器,则返回的是常量引用,如果是普通的成员,则可以通过修改该引用来修改容器内部的值。
  2. 下标访问时切记应当不要超过范围,如果想调用异常处理,则使用at。
  3. 下标访问和at访问不支持forward_list和list

删除元素

  1. 由于删除元素会改变容器的容量,故以下函数不支持array容器
  2. 删除deque中除首尾位置之外的任何元素都会使所有迭代器、引用和指针失效。指向vector或string中删除点之后位置的迭代器、引用和指针都会失效。
  3. 不能对一个空容器做出删除元素的操作。
//容器尾删除元素:vector、string、deque支持
//返回void
c.pop_back(t);

//容器首删除元素:forward_list、list、deque支持
//返回void
c.pop_front(t);

//特定位置删除元素:list、vector、string、deque。
//forward_list提供了特殊版本的erase
//erase返回删除元素之后的元素
c.erase(p) //删除插入单个,p为迭代器,若p是尾后迭代器,则该行为未定义
c.erase(b,e)//删除b~e内元素,返回e的迭代器
c.clear()//删除所有元素

特殊的forward_list操作

由于forward_list单链表并不能由后面的元素来访问前面的元素,而我们删除一个数据的时候,需要访问前面的元素并将其链接到数据后面的元素,所以原本的函数都采用不了。

//考虑到首位置采用以上操作不能增删,forward_list定义了before_begin,返回begin之前的迭代器,但是无法进行解引用。
lst.before_begin();
lst.cbefore_begin();

//在迭代器p之后插入数据(与其他顺序容器进行对比,其他的是插入到p迭代器之前,这里是插入到之后)。
//值得关注的是切勿插入尾元素之后,此种做法是未定义的。
//返回指向最后一个插入元素的迭代器
lst.insert_after(p,t);
lst.insert_after(p,n,t);
lst.insert_after(p,b,e);
lst.insert_after(p,il);

//在迭代器p之后插入数据(与其他顺序容器进行对比,其他的是插入到p迭代器之前,这里是插入到之后)。
//值得关注的是切勿插入尾元素之后,此种做法是未定义的。
//返回指向新元素的迭代器
emplace_after(p,args);

//在迭代器p之后插入数据(与其他顺序容器进行对比,其他的是插入到p迭代器之前,这里是插入到之后)。
//值得关注的是切勿插入尾元素之后,此种做法是未定义的。
//返回指向被删元素之后元素的迭代器
lst.erase_after(p);
lst.erase_after(b,e);

改变容器大小

  1. 相同的array无法进行修改大小。
  2. 如果当前大小大于所要求的大小,容器后部的元素会被删除;如果当前大小小于新大小,会将新元素添加到容器后部。
c.resize(n);  //调整c的大小为n个元素。多出被舍弃,少于部分被初始化。
c.resize(n,t);//新添加元素初始化为t

给个样例吧:

#include<iostream>
#include<vector>

using namespace std;

int main() 
{
	vector<int > v1 = { 1,2,3,4,5 };//5个元素
	v1.resize(10);
	//输出结果:1 2 3 4 5 0 0 0 0 0
	v1.resize(15, -1);
	//输出结果:1 2 3 4 5 0 0 0 0 0 -1 -1 -1 -1 -1
	v1.resize(8);
	//输出结果:1 2 3 4 5 0 0 0
	return 0;
}

值得关注的是:如果resize缩小容器,则指向被删除元素的迭代器、引用和指针都会失效;对vector、string或deque进行resize可能导致迭代器、指针和引用失效。

容器操作可能使迭代器失效

  1. 链表的指针、迭代器、引用在增删操作之后仍有效;
  2. 对于vector、string增加操作,如果存储空间被重新分配,指针、迭代器、引用失效。未重新分配则插入之前有效之后无效。对于删除操作,删除之前有效之后无效。
  3. 对于deque,增操作在首尾之外指针、迭代器、引用失效。在首尾,迭代器失效,引用指针不失效;删操作,首尾之外指迭引失效删尾,尾后迭代器失效,其他指迭引有效。删首,无影响。
  4. 建议迭代器保持在有效程序片段内,每次改变容器操作后重新定位迭代器。切记使用自定义iter 的时候每次修改之后要修改其位置。
  5. 元素末尾迭代器使用c.end(),而不是自定义的auto iter = c.end()。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值