热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

详解C++中的vector容器及用迭代器访问vector的方法

使用迭代器iterator可以更方便地解引用和访问成员,当然也包括vector中的元素,本文就来详解C++中的vector容器及用迭代器访问vector的方法,需要的朋友可以参考下

vector

vector是相同类型对象的集合。集合中的每个对象有个对应的索引。vector常被称为容器(container)。
为了使用vector,需要:

#include 
using std::vector;

vector是一个类模版(class template)。C++有函数模版和类模版。模版本身不是函数或类,必须通过指定 类型让编译器去实例化(instantiation)它。比如vector ivec。
vector是模版,不是类型。从vector得到的类型要包含元素的类型。
早期C++定义vector的元素是vector是,最后一个闭括号前必须有一个空格,如vector >。但是C++ 11不要求这样。
定义和初始化vectors

最常有的定义vectors的方法如下:

方法 解释
vector v1 默认初始化,v1是空的
vector v2(v1) v2有v1每个元素的拷贝
vector v2 = v1 等价于v2(v1)|
vector v3(n, val) v3有n个val
vector v4(n) v3有n个元素,每个元素是value-initialized
vector v5{a, b, c, ...} v5的元素即a, b, c, ...
vector v5 = {a, b, c, ...} 等价于v5{a, b, c, ...}

需要注意的是,最常用使用vector的方法就是定义一个起初为空的vector,即vector v,在运行时指定元素。
vector的列表初始化(list initializing)

上面使用花括号(curly brace)的方法是列表初始化,是C++ 11引入的。
比如,

vector articles = {"an", "a", "the"};

我们看到C++有很多初始化的方式,很多情况下它们是可以互换的,但有些时候初始化的形式是不能换的:
当使用拷贝初始化形式(即使用=),只能提供单个初始化器
当提供in-class初始化,只能是拷贝初始化或者花括号
列表初始化只能使用花括号,不能是圆括号
有关value-initialized

前面提到vector ivec(10)这种只指定元素个数的初始化方法,每个元素是value-initialized。即:
对内置类型,值为0
对类类型,使用默认初始化
花括号,圆括号

vector v1(10); // 10个元素,都是0
vector v1{10}; // 1个元素,是10
vector v1{10, 1}; // 2个元素,分别是10, 1
vector v1(10, 1); // 10个元素,都是1

需要注意的是,使用{}并不一定就是列表初始化;它表示: 如果可能的话,使用列表初始化。

vector v5{"hi"}; // ok, list initialization
vector v6("hi"); // error: cann't construct vector from string lieral
vector v7{10}; // has ten default-initialized value.

上面的v7就使用花括号指定个数,而不是列表初始化。
向vector添加元素

使用push_back方法。
重要概念:vector高效增长:
标准要求vector的实现能够在运行时高效添加。如果在定义vector时指定了大小,就显得没必要,甚至导致 差的性能。总之,一般直接开始定义一个空的vector。
另外,我们要确保即使循环改变了vector的大小,循环也是正确的。因此,不能在range for里面向vector添加元素。
其它的vector操作

最常用的操作有:

方法
v.empty()
v.size()
v.push_back(t)
v[n]
==, !=, <, <=, >, >=

类似的,v.size()返回的类型也是size_type的。需要注意的是,模版类的类型始终是包括元素类型的,

vector::size_type // ok
vector::size_type // error

关于下标访问,它只能访问已经存在的元素,不会添加。

vector ivec;
cout <

  
迭代器
尽管我们可以使用下标来访问字符串中的字符或vector的元素,但更一般的机制是使用迭代器(iterator)。
所有的容器都支持迭代器,但仅少数几个支持下标操作。
合法的迭代器:

  • 指示某个元素
  • 指示最后一个元素的下一个位置
  • 其它的迭代器都是不合法的。
  • 使用迭代器

使用begin和end成员函数。

// b 指示第一个元素;e 指示最后一个元素的下一个位置
auto b = v.begin(), e = v.end();

一般我们不必关心迭代器的准确类型,所以直接使用auto。
end返回的迭代器一般被称为off-the-end迭代器,或者缩写为end迭代器。
显然,如果一个容器为空,begin返回的和end返回的相同。
迭代器的操作

| 方法 | 解释 | | iter | 返回指示元素的引用 | | iter->mem | 解引用iter,并获取名字为mem的成员,等价于 (iter).mem | | ++iter | 增加iter,指示下一个 | | --iter | 减小iter,指示前一个 | | == , != | 比较 |
下面是把遇到空白字符前的字符转成大写。

for(auto it = s.begin(); it != s.end() && !isspace(*it); ++it)
  *it = toupper(*it);

熟悉C或者Java语言的人可能需要习惯C++里面for循环一般都是使用!=结束,而不是使用<。 这是因为,所有的容器的迭代器都定义了!=和==方法;而绝大部份迭代器没有<方法。通过使用!=,我们可以不必 关心处理容器的准确类型。
迭代器的类型

就像我们不知道vector或string的size_type的准确类型,我们一般也不知道迭代器的准确类型。
库类型的迭代器定义了iterator和const_iterator两种类型。

vector::iterator it; // 可读,可写
vector::iterator it2; // 可读,可写
vector::const_iterator it3; // 可读,不能写

const_iterator的行为类似一个const指针。就像const指针,const_iterator不能修改所指示的元素。如果 一个vector或者字符串是const的,那么只能使用const_iterator。
如果对象是const的,那么begin和end返回的就是const_iterator;如果对象不是const的,返回的就是iterator。 但这种行为有时不是我们想要的,即针对非const对象,我们也希望得到const_iterator。C++ 11引入了两个新的函数, cbegin和cend解决了这一问题。

auto it3 = v.cbegin();

解引用和访问成员

当对迭代器解引用时,得到的是其指示的对象。如果该对象是个类类型的,我们可能要访问其的成员。举个例子,一个字符串的vector可能想知道 给定元素是否为空,可以使用(*it).empty()。
需要注意的是,(*it).empty()这个括号是必须的。否则,点操作符直接作用于it。因此,*it.empty()是错误的。
为了简化这种表示,语言定义了箭头操作符(->),它把解引用和成员访问组合为一个符号,即it->empty()。
迭代器的算术

自增与自减是所有迭代器都支持的操作。
而对于string和vector的迭代器,还支持额外的算术操作。
| 方法 | | iter + n | | iter - n | | iter1 += n | | iter2 -= n | | iter1 - iter2 | | >, >=, <, <= |
比如,计算vector中间位置,

auto mid = vi.begin() + vi.size() / 2;

需要注意的是,迭代器的相加是不合法的。


推荐阅读
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • Ralph的Kubernetes进阶之旅:集群架构与对象解析
    本文深入探讨了Kubernetes集群的架构和核心对象,详细介绍了Pod、Service、Volume等基本组件,以及更高层次的抽象如Deployment、StatefulSet等,帮助读者全面理解Kubernetes的工作原理。 ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
  • 本文详细探讨了Java中StringBuffer类在不同情况下的扩容规则,包括空参构造、带初始字符串和指定初始容量的构造方法。通过实例代码和理论分析,帮助读者更好地理解StringBuffer的内部工作原理。 ... [详细]
  • 本文探讨了领域驱动设计(DDD)的核心概念、应用场景及其实现方式,详细介绍了其在企业级软件开发中的优势和挑战。通过对比事务脚本与领域模型,展示了DDD如何提升系统的可维护性和扩展性。 ... [详细]
  • 深入了解 Windows 窗体中的 SplitContainer 控件
    SplitContainer 控件是 Windows 窗体中的一种复合控件,由两个可调整大小的面板和一个可移动的拆分条组成。本文将详细介绍其功能、属性以及如何通过编程方式创建复杂的用户界面。 ... [详细]
  • 实体映射最强工具类:MapStruct真香 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 本文探讨了在Linux系统上使用Docker时,通过volume将主机上的HTML5文件挂载到容器内部指定目录时遇到的403错误,并提供了解决方案和详细的操作步骤。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 作为一名专业的Web前端工程师,掌握HTML和CSS的命名规范是至关重要的。良好的命名习惯不仅有助于提高代码的可读性和维护性,还能促进团队协作。本文将详细介绍Web前端开发中常用的HTML和CSS命名规范,并提供实用的建议。 ... [详细]
  • 本文探讨了在 ASP.NET MVC 5 中实现松耦合组件的方法。通过分离关注点,应用程序的各个组件可以更加独立且易于维护和测试。文中详细介绍了依赖项注入(DI)及其在实现松耦合中的作用。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 网易严选Java开发面试:MySQL索引深度解析
    本文详细记录了网易严选Java开发岗位的面试经验,特别针对MySQL索引相关的技术问题进行了深入探讨。通过本文,读者可以了解面试官常问的索引问题及其背后的原理。 ... [详细]
author-avatar
极御云安全
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有