详解C++中的vector容器及用迭代器访问vector的方法
vector
vector是相同类型对象的集合。集合中的每个对象有个对应的索引。vector常被称为容器(container)。
为了使用vector,需要:
#include <vector> using std::vector;
vector是一个类模版(class template)。C++有函数模版和类模版。模版本身不是函数或类,必须通过指定 类型让编译器去实例化(instantiation)它。比如vector<int> ivec。
vector是模版,不是类型。从vector得到的类型要包含元素的类型。
早期C++定义vector的元素是vector是,最后一个闭括号前必须有一个空格,如vector<vector<int> >。但是C++ 11不要求这样。
定义和初始化vectors
最常有的定义vectors的方法如下:
方法 | 解释 |
---|---|
vector |
默认初始化,v1是空的 |
vector |
v2有v1每个元素的拷贝 |
vector |
等价于v2(v1)| |
vector |
v3有n个val |
vector |
v3有n个元素,每个元素是value-initialized |
vector |
v5的元素即a, b, c, ... |
vector |
等价于v5{a, b, c, ...} |
需要注意的是,最常用使用vector的方法就是定义一个起初为空的vector,即vector<T> v,在运行时指定元素。
vector的列表初始化(list initializing)
上面使用花括号(curly brace)的方法是列表初始化,是C++ 11引入的。
比如,
vector<string> articles = {"an", "a", "the"};
我们看到C++有很多初始化的方式,很多情况下它们是可以互换的,但有些时候初始化的形式是不能换的:
当使用拷贝初始化形式(即使用=),只能提供单个初始化器
当提供in-class初始化,只能是拷贝初始化或者花括号
列表初始化只能使用花括号,不能是圆括号
有关value-initialized
前面提到vector<int> ivec(10)这种只指定元素个数的初始化方法,每个元素是value-initialized。即:
对内置类型,值为0
对类类型,使用默认初始化
花括号,圆括号
vector<int> v1(10); // 10个元素,都是0 vector<int> v1{10}; // 1个元素,是10 vector<int> v1{10, 1}; // 2个元素,分别是10, 1 vector<int> v1(10, 1); // 10个元素,都是1
需要注意的是,使用{}并不一定就是列表初始化;它表示: 如果可能的话,使用列表初始化。
vector<string> v5{"hi"}; // ok, list initialization vector<string> v6("hi"); // error: cann't construct vector from string lieral vector<string> 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<int>::size_type // ok vector::size_type // error
关于下标访问,它只能访问已经存在的元素,不会添加。
vector<int> ivec; cout << ivec[0]; // error for (decltype(ivev.size()) ix = 0; ix != 10; ix++) ivec[ix] = ix; // disaster: has no element
迭代器
尽管我们可以使用下标来访问字符串中的字符或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<int>::iterator it; // 可读,可写 vector<int>::iterator it2; // 可读,可写 vector<int>::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;
需要注意的是,迭代器的相加是不合法的。
相关文章
- vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
- 这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
- 这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
- 本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
- 本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
pytorch::Dataloader中的迭代器和生成器应用详解
这篇文章主要介绍了pytorch::Dataloader中的迭代器和生成器应用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-30- 整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
- 这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
- 这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
- 这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
- 本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
- 这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
- 这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
- 这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
- 虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
- 这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
- map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
- 这篇文章主要介绍了C++ 约瑟夫环问题案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-15
- 这篇文章主要介绍了C++中cin的用法详细,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
- 本篇文章是对C++中的常见编译错误进行了详细的分析介绍,需要的朋友参考下...2020-04-25