顺序容器的添加、访问、删除操作以及forward_list的特殊操作,还有迭代器失效问题。

一、向容器添加元素

// array不支持这些操作
// forward_list有自己撰于的版本的insert和emplace
// forward_list不支持push_back和emplace_back
// vector和string不支持push_front和emplace_front
c.push_back(t); 在c的尾部创建一个值为t或由arg创建的元素
c.emplace_back(arg); 函数返回void
c.push_front(t); 在c的头部创建一个值为t或由arg创建的元素</span>
c.emplace_front(arg); 函数返回void
c.insert(p, t); 在迭代器p指向的元素之前创建一个值为t或有arg创建的元素
c.emplace(p, t); 函数返回指向新添加元素的迭代器
c.insert(p, n, t); 在迭代器p指向元素之前插入n个值为t的元素,函数返回指向新添加的第一个元素的迭代器,若n为0,则返回p
c.insert(p, b, e); 在迭代器p指向元素之前插入迭代器b到e(不包括e)之间的元素,b和e不能指向c中元素,返回新添加的第一个元素的迭代器,若范围为空,则返回p
c.insert(p, il); 在迭代器p指向元素之前插入由花括号包围的初始值列表 il 的元素,函数返回指向新添加的第一个元素的迭代器,若列表为空,则返回p

当容器调用push或insert成员时,这些对象被拷贝到容器中,而进行emplace操作时,则是将参数传递给容器的构造函数,emplace使用这些参数在容器里直接构造一个元素。

因此,emplace的参数必须与元素类型的构造函数的参数相匹配。

二、访问元素

除了array、每个顺序容器都有一个front成员函数,除了forward_list之外的所有顺序容器都有一个back成员函数,这两个操作分别返回首元素和尾元素的引用

// at和下标操作值适用于string、vector、deque和array
// back不适用于forward_list
c.back(); 返回c的尾元素的引用,若c为空,则行为未定义
c.front(); 返回c的首元素的引用,若c为空,则行为未定义
c[n]; 返回c中下标为n的元素的引用,n是一个无符号整数
c.at(n); 返回下标为n的引用。如果下标越界,则抛出一个 out_of_range异常

三、删除元素

// 这些操作不适用于array
// forward_list有特殊版本的erase,并且它不支持pop_back;
// vector和string不支持pop_front
c.pop_back(); 返回c中的尾元素/首元素,若c为空,则函数行为未定义
c.pop_front(); 函数返回void
c.clear(); 删除c中所有元素,返回void
c.erase(p); 删除c中p指向的元素,返回指向被删元素之后元素的迭代器,如果p指向尾元素,则返回尾后迭代器,若p为尾后迭代器,则行为未定义
c.erase(b, e); 删除迭代器b和e(不包括e)之间的元素,返回指向被删元素之后元素的迭代器, 若e为尾后迭代器,则返回e

四、特殊的forward_list操作

由于在单项链表中,没有简单的方法来获取一个元素的前驱,所以在forward_list中定义了首前迭代器。

lst.before_begin();          返回指向链表首元素之前不存在的元素的迭代器,c开头的是const_iterator版本
lst.cbefore_begin(); 不能解引用此迭代器 lst.inert_after(p, t); 在迭代器p之后插入元素,t是一个对象
lst.inert_after(p, n, t); n是数量
lst.inert_after(p, b, e); b、e表示范围的一对迭代器(不能指向lst)
lst.inert_after(p, il); il是一个花括号的初始化列表,返回一个指向插入的最后一个元素的迭代器,如果范围为空,返回p,如果p为尾后迭代器,则行为未定义
lst.emplace_after(p, arg); 在p指向的位置之后插入由arg构造的元素,返回指向这个新元素的迭代器,如果p是尾后迭代器,则行为未定义
lst.erase_after(p); 删除p之后的元素,或删除b到e(不包括e)之间的元素,返回一个指向被删元素之后元素的迭代器
lst.erase_after(b, e); 如果不存在这样的元素,返回尾后迭代器,若p指向lst的尾元素,或p是lst的尾后迭代器,则行为未定义。

在forwar_list中添加或删除元素时,我们要关注的是:指向要处理的元素的迭代器和其前驱迭代器。

例:从forward_list中删除奇数

forward_list<int> flst = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto prev = flst.before_begin(); // 获取首前迭代器
auto curr = flst.begin();
while (curr != flst.end()){
if(*curr % 2)
curr = flst.erase_after(prev); // 删除当前元素,将curr定位到新的第一个元素
else
prev = curr ++; // 移动首前元素和当前元素
}

五、改变容器大小

// resize不适用于array
c.resize(n); 调整c的大小为n个元素,若n < c.size(); 则多出的元素被丢弃,否则对新添加的元素进行值初始化
c.resize(n, t); 调整c的大小为n个元素,任何新添加的元素都被初始化为t
// 如果resize缩小了容器,则指向被删除的元素的迭代器、引用和指针都会失效,对vector、string和deque进行resize可能导致迭代器、引用和指针失效

六、容器操作和迭代器失效问题

向容器中添加元素后:

1. 如果容器时vector或string,且存储空间被重新分配,则指向容器的迭代器、指针和引用都会失效,如果存储空间未重新分配,则指向插入元素之前的迭代器、指针和引用都有效,指向插入元素之后元素的迭代器、指针和引用都会失效。

2. 对于deque,插入到除首尾位置之外的任何位置都会导致迭代器、引用和指针失效,如果在首尾位置添加元素,迭代器会失效,但指向存在的元素的引用和指针不会失效。

3. 对于list和forward_list,指向容器的迭代器(包括尾后迭代器和首前迭代器)、指针和引用都有效

容器在删除元素后:

1.  对于list和forward_list,指向容器的迭代器(包括尾后迭代器和首前迭代器)、指针和引用都有效

2. 对于deque,如果在首尾之外的任何位置删除元素,那么指向删除元素外其他元素的迭代器、引用和指针也会失效。如果是删除deque的尾元素,则尾后迭代器失效,但其他迭代器、引用和指针不受影响; 如果删除首元素,这些也不会受影响。

3. 对于vector和string,指向被删除元素之前元素的迭代器、引用和指针扔有效

当我们删除元素时,尾后迭代器总是会失效!

因此,必须保证每次改变容器的操作之后都正确的重新定位迭代器,还有,不要保存end返回的尾后迭代器。

C++ Primer : 第九章 : 顺序容器的操作以及迭代器失效问题的更多相关文章

  1. C++ Primer : 第九章 : 顺序容器的定义、迭代器以及赋值与swap

    顺序容器属于C++ STL的一部分,也是非常重要的一部分. 顺序容器包括: std::vector,包含在头文件<vector>中 std::string, 包含在头文件<strin ...

  2. C++ Primer 第九章 顺序容器

    由于书籍上写的已经很经典了,故大部分用图片的形式来阐述概念,代码纯手打进行验证. 1.顺序容器类型:vector.deque.list.forword_list.array.string. 2.顺序容 ...

  3. C++ Primer 读书笔记: 第9章 顺序容器

    第9章 顺序容器 引: 顺序容器: vector 支持快速随机访问 list 支持快速插入/删除 deque 双端队列 顺序容器适配器: stack 后进先出栈 queue 先进先出队列 priori ...

  4. [C++ Primer] 第9章: 顺序容器

    顺序容器概述 顺序容器的类型有: 类型 说明 vector 可变长度数组. 支持快速随机访问. deque 双端队列. 支持快速随机访问. list 双向链表. 只支持双向顺序访问. forward_ ...

  5. 《C++ Primer》笔记 第9章 顺序容器

    顺序容器类型 类型 解释 vector 可变大小数组.支持快速随机访问.在尾部之外的位置插入或删除元素可能很慢 deque 双端队列.支持快速随机访问.在头尾位置插入.删除速度很快 list 双向链表 ...

  6. cb09a_c++_顺序容器的操作2-在顺序容器中添加元素_插入数据

    cb09a_c++_顺序容器的操作2在顺序容器中添加元素vector不能向前插入数据,list可以用insertc.push_back(t);c.push_front(t);c.insert(p,t) ...

  7. cb14a_c++_顺序容器的操作7_赋值与交换(swap)_vector转list

    cb14a_c++_顺序容器的操作7_赋值与交换(swap) vector数据赋值给list, slist.assign(svec.begin(), svec.end());//这样可以转 svec- ...

  8. ca13a_c++_顺序容器的操作6删除元素

    /*ca13a_c++_顺序容器的操作6删除元素c.erase(p) //删除迭代器p指向的位置c.erase(b,e) //删除b to e之间的数据,迭代器b包括,e不包括c.clear()//删 ...

  9. ca12a_c++顺序容器的操作5_访问容器中的数据元素

    ca12a_c++顺序容器的操作5_访问容器中的数据元素访问元素:c.back()..显示最后一个数据c.front() ..显示第一个数据c[n],n就是下标,适合vector与dequec.at( ...

随机推荐

  1. 一模 (5) day1

    第一题: 题目大意:求出1-10^n 这些数中,包含数字3的有多少个. n<=1000: 解题过程: 1.这题一看就是高精度+递推..如果n=1000,那么假设个位是3,其他999位任意..那么 ...

  2. zabbix3.0部署(LAMP)

    0.1 初始化 #!/bin/sh yum clean all systemctl stop firewalld.service systemctl disable firewalld.service ...

  3. html,body最顶层元素.

    1,元素百比分是相对父元素,所有元素默认父元素是body. absolute,fixed[只有一个父元素,浏览器窗口]除外[浏览器窗口,为父元素].css3:vh,vw也永远相对,浏览器窗口.heig ...

  4. ios 常用的小框架

    在ios开发中,一些请求 kvc 下拉列表  图片请求等等自己手写代码的话非常麻烦,还容易出现一系列的问题,现在整理了一些常用的一些小框架. 其中MJExtension 和 MJRefresh 这两个 ...

  5. PL/SQL : Procedural Language / Structual Query Language and it is an exrension to SQL.

    SQL is not very flexible and it cannot be made to react differently to differing sutuations easily. ...

  6. java static

    一. static代表着什么 在Java中并不存在全局变量的概念,但是我们可以通过static来实现一个“伪全局”的概念,在Java中static表示“全局”或者“静态”的意思,用来修饰成员变量和成员 ...

  7. maven的简单安装与配置

    什么是Maven? Maven可以被理解成"知识的积累",也可以被翻译为"专家".它是一个项目管理工具. 它的主要服务即源于java平台的项目构建.依赖管理和项 ...

  8. VMWare三种工作模式 :bridge、host-only、nat

    VMWare提供了三种工作模式,它们是bridged(桥接模式).NAT(网络地址转换模式)和host-only(主机模式).要想在网络管理和维护中合理应用它们,你就应该先了解一下这三种工作模式.这里 ...

  9. C# 启动关闭.exe进程(转)

    后台代码: 1 using System.Diagnostics;  2 3 protected void Button1_Click(object sender, EventArgs e)4     ...

  10. php的分页查询建立分页类

    创建一个分页类 <?php /** file: page.class.php 完美分页类 Page */ class Page { private $total; //数据表中总记录数 priv ...