「C++笔记」vector:C++中的新式“数组”
「C++笔记」这个系列是我最近学习新版本的 C++ 版本的笔记,材料主要是《A Tour of C++ Third Edition》。这本书的作者就是 C++ 的作者 Bjarne Stroustrup,所以也会记录一些他的思想。
版本主要是 20/23 这些,不过我对 11 的了解也不完善,所以可能也会有一些大家早就知道的。
介绍
C++ 中,有一种容器叫做 vector,它的定义和作用与数组差不多,都是同一种类型的元素序列,在内存中连续存储。
但是在实现的时候,要比数组要复杂一些:大致来说,它会动态分配内存空间,然后有三个指针指向元素序列的开头和结尾,以及空闲区域的末尾(有的会用偏移量记录)。所以 vector 的结构是一个内存分配器和三个指针。如下:
不过 vector 有一些新的特性,非常方便使用,就连 C++ 创始人 Bjarne Stroustrup 都推荐使用vector
,如下是《A Tour of C++ Third Edition》中的内容,并且也强调不用担心效率、性能问题:
容器还有个很好的特性就是不用担心内存回收。因为 C++ 没有垃圾回收机制,很容易粗心使得内存只分配,不回收,最后占用一大堆内存,这也是 C++ 一直被诟病的问题。但是容器很容易解决了这个问题,因为构造函数分配了内存,最后不用了会有析构函数回收(我是看这书才反应过来析构函数的作用是这个,之前一直当作结束生命周期的,没反应过来)。所以使用 vector 要比数组好很多,不然很容易忘记最后free
或者delete[]
。
用法
相似
简单地声明和定义一个 vector 与数组差不多,如下:
vector<int> v1;
v1= {1, 2, 3, 4};
vector<int> v1 = {1, 2, 3, 4};
这里的<>
中的int
表示这里的元素类型是int
,其余部分会发现和数组一样,比如赋值是大括号,序号从 0 开始等等。
同样,我们可以预先声明 vector 的大小:
vector<int> v2(23);
上面这个 vector 的尺寸是 23(需要注意不是数组的方括号,而是圆括号)。
如果你想声明一个整数指针的序列,那么使用下面的样式:
vector<int*> v3;
新玩意
本文无意做翻译文档的作用,所以只记录一些我觉得有用,或者学了之后一通百通的内容。
声明尺寸与初始值
vector 有一些新的特性:假设你想声明有 10 个整数的数组,但是这个数组的初始值为 3。按照数组的方法,需要先声明一个固定尺寸的数组,然后用循环赋值。如下:
int a[10];
for (int i=0; i<10; i++) {
a[i]=3;
}
但是 vector 就很方便了,声明的时候就能搞定,如下:
vector<int> a(10, 3);
新增单个元素
增加元素需要使用成员函数push_back()
(给结尾)和insert()
。
前者如下:
#include <iostream>
using namespace std;
int main() {
std::vector<int> v1 = {1, 2, 3, 4};
//循环输出
for (const auto& x : v1)
cout << x << ' ';
cout << '\n';
//在尾部添加两个元素
v1.push_back(1);
v1.push_back(2);
//循环输出
for (const auto& x : v1)
cout << x << ' ';
cout << '\n';
}
输出:
1 2 3 4
1 2 3 4 1 2
后者麻烦一些,如下:
#include <iostream>
#include <valarray>
using namespace std;
int main() {
std::vector<int> v1 = {1, 2, 3, 4};
//循环输出
for (const auto& x : v1)
cout << x << ' ';
cout << '\n';
//插入到从头开始第三个位置(因为从0开始,所以+2)
v1.insert(v1.begin()+2,100);
//循环输出
for (const auto& x : v1)
cout << x << ' ';
cout << '\n';
}
输出:
1 2 3 4
1 2 100 3 4
代码中的v1.begin()+2
是位置,这个参数也可以设置成中间的某个元素的位置。
valarray:vector向量计算
vector 虽然有向量的意思,但是并不能进行向量计算。不过标准库<valarray>
里提供了一个 vector 类的模板 valarray,可以像 SIMD 一样进行计算,这使得处理一些数据的时候方便了很多:
#include <iostream>
#include <valarray>
using namespace std;
int main() {
valarray<int> v1 = {1, 2, 3, 4};
valarray<int> v2 = {4, 3, 2, 1};
//这里会对整个valarray进行计算,不用自己写循环
valarray<int> v3 = v1*v2 + v1/v2 + v1 * 12;
//循环输出
for (const auto& x : v3)
cout << x << '\n';
}
其实如果你使用过其他现代语言的数组,会发现很多成员函数都是相似的,语法除了名字几乎没什么不同,只不过一开始上手还是需要熟悉一下。
希望能帮到有需要的人~
参考资料
《A Tour of C++ Third Edition》
std::vector - cppreference.com:C++ vector 中文文档,很多本文没有提到的功能都可以自行查看这里。