《21天学通C++(第7版)》——17.2 典型的vector操作

简介:

本节书摘来自异步社区出版社《21天学通C++(第7版)》一书中的第17章,第17.2节,作者: 【美】Siddhartha Rao, 【德】Nicolai M. Josuttis,更多章节内容可以访问云栖社区“异步社区”公众号查看。

17.2 典型的vector操作

21天学通C++(第7版)
std::vector类的行为规范和公有成员是由C++标准定义的,因此,遵循该标准的所有C++编程平台都支持本章将介绍的vector操作。

17.2.1 实例化vector

vector是一个模板类,需要使用第14章介绍的方法进行实例化。要实例化vector,需要指定要在该动态数组中存储的对象类型:
image

要声明指向list中元素的迭代器,可以这样做:
image

如果需要可用于修改值或调用非const函数的迭代器,可使用iterator代替const_iterator。

鉴于std::vector有多个重载的构造函数,您可在实例化vector时指定它开始应包含的元素数以及这些元素的初始值,还可使用vector的一部分来实例化另一个vector。

程序清单17.1演示了几种实例化vector的方式。

程序清单17.1 各种实例化std::vector的方式:指定长度和初始值以及复制另一个vector中的值
image

分析:
上述代码演示了如何为整型具体化vector类,即实例化一个存储整型数据的vector。该vector名为vecIntegers,它使用了默认构造函数。在不知道容器最小需要多大,即不知道要存储多少个整数时,默认构造函数很有用。实例化vector的第2种和第3种方式如第10行和第13行所示,在这里,程序员知道vector至少应包含10个元素。注意,这并没有限制容器最终的大小,而只是设置了初始大小。第4种形式如第16行和第18行所示,它使用一个vector实例化另一个vector的内容,即复制vector对象或其一部分。这是所有STL容器都支持的构造函数。最后一种形式是使用迭代器。vecSomeElementCopied包含vecWithTenElements的前5个元素。

第4个构造函数只能用于类型类似的对象,因此可使用一个包含整型对象的vector来实例化vecArrayCopy——另一个整型vector,但如果其中一个vector包含的对象类型为float,代码将不能通过编译。

cbegin()和cend()是否导致编译错误?

如果您使用的编译器没有遵循C++11标准,请使用begin()和end()分别代替该程序中的cbegin()和cend()。

cbegin()和cend()的不同之处(优点)在于,它们返回一个迭代器,但较老的编译器不支持它们。
17.2.2 使用push_back()在末尾插入元素
实例化一个整型vector后,接下来需要在vector中插入元素(整数)。在vector中插入元素时,元素将插入到数组末尾,这是使用成员方法push_back完成的:
image

程序清单17.2演示了如何使用push_back()在std::vector中动态地添加元素。

程序清单17.2 使用push_back在vector中插入元素
image

输出:
.image

分析:
第9~12行的push_back是vector类的一个公有成员方法,用于在动态数组末尾插入对象。请注意函数size ()的用法,它返回vector中存储的元素数。

C++11
初始化列表
C++11通过std::initialize_list<>支持初始化列表,让您能够像处理静态数组那样,在实例化vector的同时初始化其元素:
image

如果在程序清单17.2中使用这种语法,可节省3行代码,但这里没有这样做,因为编写本书时,Microsoft Visual C++ 2010编译器的std::vector实现不支持初始化列表。

17.2.3 使用insert()在指定位置插入元素

push_back在vector末尾插入元素。如果要在中间插入元素,该如何办呢?很多STL容器(包括std::vector)都包含insert()函数,且有多个重载版本。

其中一个版本让您能够指定插入位置:
image

另一个版本让您能够指定插入位置、要插入的元素数以及这些元素的值(都相同):
image

还可将另一个vector的内容插入到指定位置:
image

可使用迭代器(通常是由begin()或end()返回的)告诉insert()您想将新元素插入到什么位置。

也可将该迭代器设置为STL算法(如std::find()函数)的返回值。std::find()可用于查找元素,然后在这个位置插入另一个元素(这将导致查找的元素向后移)。
程序清单17.3演示了vector::insert()的各种重载版本。

程序清单17.3 使用函数vector::insert在指定位置插入元素

image

输出:
image

分析:
上述代码演示了insert函数的强大功能,它让您能够将值插入到容器中间。第17行的vector包含4个元素,每个元素都被初始化为90;然后,使用了成员函数vector::insert的各种重载版本。第23行在开头添加了一个元素;第26行在末尾添加了两个元素,它们的值都是45。第35行演示了如何将一个vector的元素插入到另一个vector中间(这里是第一个元素后面,偏移量为1)。

虽然函数vector::insert功能众多,但给vector添加元素时,应首选push_back()。

请注意,将元素插入vector时,insert()可能是效率最低的(插入位置不是末尾时),因为在开头或中间插入元素时,将导致vector类将后面的所有元素后移(为要插入的元素腾出空间)。根据容器中包含的对象类型,这种移动操作可能需要调用复制构造函数或赋值运算符,因此开销可能很大。在上述例子中,vector包含的是int对象,移动开销不是很大。但在其他情况下,情况可能并非如此。

如果需要频繁地在容器中间插入元素,应选择使用第18章将介绍的std::list。

您使用的C++编译器是否较老

在程序清单17.3中,函数DisplayVector()使用了C++11关键字auto来声明迭代器的类型,如第6行所示。对于这个示例以及后面的示例,如果要使用非C++11编译器编译它们,需要将auto替换为显式类型,这里为vector::const_iterator。

因此,如果您使用的是较老的编译器,需要将DisplayVector()修改成下面这样:
image

17.2.4 使用数组语法访问vector中的元素

可使用下列方法访问vector的元素:使用下标运算符([])以数组语法方式访问;使用成员函数at();使用迭代器。

程序清单17.1演示了如何创建一个包含10个元素的vector实例:
image

可使用类似于数组的语法访问并设置各个元素:

image

程序清单17.4演示了如何使用下标运算符([])访问元素。

程序清单17.4 使用数组语法访问vector中的元素
image

输出:
image

分析:
在第17、21和23行,像使用静态数组那样,使用下标运算符([])访问并设置了vector的元素。下标运算符接受一个从零开始的元素索引,与静态数组一样。注意到第15行的for循环将索引与vector::size()进行比较,确保它跨越vector的边界。

使用[]访问vector的元素时,面临的风险与访问数组元素相同,即不能超出容器的边界。使用下标运算符([ ])访问vector的元素时,如果指定的位置超出了边界,结果将是不确定的(什么情况都可能发生,很可能是访问违规)。

更安全的方法是使用成员函数at():
image

at()函数在运行阶段检查容器的大小,如果索引超出边界(无论如何都不能这样做),将引发异常。

下标运算符([ ])只有在保证边界完整性的情况下才是安全的,如前一个例子所示
17.2.5 使用指针语法访问vector中的元素
也可使用迭代器以类似于指针的语法访问vector中的元素,如程序清单17.5所示。

程序清单17.5 使用指针语法(迭代器)访问vector中的元素

image

输出:
image

分析:
在这个例子中,迭代器有点像指针,迭代器的用法很像指针算术运算,如第25和29行所示。在第25行,使用了解除引用运算符(*)来访问存储在vector中的值,而第29行使用了运算符++递增迭代器,使其指向下一个元素。第21行使用了std::distance来计算元素的偏移量(相对于开头的位置),这是根据begin()和指向元素的迭代器计算得到的。

17.2.6 删除vector中的元素

除支持使用push_back方法在末尾插入元素外,vector还支持使用pop_back函数将末尾的元素删除。使用pop_back将元素从vector中删除所需的时间是固定的,即不随vector存储的元素个数而异。程序清单17.6演示了如何使用函数pop_back删除vector末尾的元素。

程序清单17.6 使用pop_back删除最后一个元素

image

输出:
image

分析:
上述输出表明,第29行的pop_back函数将vector的最后一个元素删除,从而减少了vector包含的元素数。第32行再次调用size(),以证明vector包含的元素少了一个,如输出所示。

在程序清单17.3中,DisplayVector()只能接受整型vector作为参数,而在程序清单17.6中,它是个模板函数(第4-13行)。这有助于将该模板函数重用于浮点型vector:
image

该模板函数接受任何类型的vector作为参数,只要该类型支持运算符,且其返回值可被cout理解。*
本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

相关文章
|
29天前
|
存储 C++ 容器
【C++】vector的底层剖析以及模拟实现
【C++】vector的底层剖析以及模拟实现
|
1月前
|
存储 算法 测试技术
C++:Vector的使用
C++:Vector的使用
|
18天前
|
人工智能 机器人 C++
【C++/Python】Windows用Swig实现C++调用Python(史上最简单详细,80岁看了都会操作)
【C++/Python】Windows用Swig实现C++调用Python(史上最简单详细,80岁看了都会操作)
|
1月前
|
存储 JSON 安全
【C++ JSON库 json值的创建手段】深入探究C++中JSON对象定位与操作:从引用到回调函数
【C++ JSON库 json值的创建手段】深入探究C++中JSON对象定位与操作:从引用到回调函数
66 0
|
3天前
|
存储 缓存 编译器
【C++进阶(五)】STL大法--list模拟实现以及list和vector的对比
【C++进阶(五)】STL大法--list模拟实现以及list和vector的对比
|
3天前
|
编译器 C++
【C++进阶(三)】STL大法--vector迭代器失效&深浅拷贝问题剖析
【C++进阶(三)】STL大法--vector迭代器失效&深浅拷贝问题剖析
|
14天前
|
存储 算法 编译器
【C++初阶】STL详解(三)vector的介绍与使用
【C++初阶】STL详解(三)vector的介绍与使用
34 0
|
14天前
|
存储 编译器 C++
【C++初阶】STL详解(四)vector的模拟实现
【C++初阶】STL详解(四)vector的模拟实现
45 1
|
19天前
|
存储 编译器 C++
【C++初阶】10. vector的使用及模拟实现
【C++初阶】10. vector的使用及模拟实现
49 1
|
25天前
|
C语言 C++
C/C++文件读取操作
C/C++文件读取操作