跳到主要内容 C++ Vector 容器详解 | 极客日志
C++ 算法
C++ Vector 容器详解 本文详细介绍了 C++ 标准库中的 vector 容器。内容包括 vector 的基本概念、动态扩容机制、多种构造方式、迭代器使用(begin/end/rbegin/rend)、容量管理函数(size/capacity/reserve/resize/shrink_to_fit)、元素访问操作(operator[]/at/front/back)以及修改操作(assign/push_back/pop_back/insert/erase/swap/clear)。重点讲解了 vector 迭代器失效的场景及正确处理方法,并对比了 reserve 与 resize 的区别。适合希望深入理解 C++ 动态数组特性的开发者阅读。
灭霸 发布于 2026/3/30 更新于 2026/4/13 3 浏览一、vector 的介绍
vector - C++ Reference
1.1 vector 是表示可变大小数组的序列容器。
1.2 和数组一样,vector 也同样使用连续的存储空间来存储元素。也就意味着可以通过下标访问 vector 的每个元素,访问效率和数组一样高效。但和数组不同的是,vector 的 size 是可以动态改变的,并且容器会自动处理存储大小。
1.3 本质上,vector 使用动态分配数组来存储它的元素。当新元素插入时,原数组为了增加存储空间需要被重新分配大小。其做法是,分配一个新数组,然后将原数组中所有元素拷贝到新数组中。但这是一个时间消耗很大的操作,因此,每当有新元素插入时,vector 并不会每次都选择重新分配数组大小。
1.4 vector 分配空间的策略:vector 会分配一些额外的空间以适应可能的元素插入操作,因为存储空间要比实际需要的存储空间更大,不同的编译器会采用不同的策略来权衡空间的使用和重新分配。在 VS2022 下 vector 每次是以 1.5 倍的方式进行扩容,g++ 则是以 2 倍的方式进行扩容。
vector<int > v; int ca = v.capacity (); for (int i = 0 ; i < 100 ; i++) { v.push_back (i); if (ca != v.capacity ()) {
1.5 因此,相较于数组,vector 会消耗更多的内存以适应动态增长和高效的内存管理。
1.6 和其他的动态顺序容器相比 (deques, list 和 forward_list),vector 在访问元素时更高效,在末尾插入和删除元素的效率也相对高效。对于其他位置的插入和删除元素,vector 的操作效率会更低,并且迭代器和引用的一致性不如 list 和 forward_list。
二、vector 的使用
2.1 构造函数 (constructor) allocator 指的是内存池,是 C++ 内存分配的一个类模板,allocator_type 是一个模板参数。explicit 代表该构造函数禁止隐式类型转换。
2.1.1 默认构造
2.1.2 使用 n 个 val 进行构造 vector
2.1.3 使用一段迭代器区间构造 vector 【注意】使用迭代器区间构造 vector 时可以使用其他容器的迭代器区间去初始化一个 vector,但数据类型需要匹配 。
例如:无法使用 vector 类型的 vector 迭代器区间构造 int 类型的 vector。
vector<int > v1 (3 , 3 ) ; vector<vector<int >> v2 (2 , v1);
2.1.4 拷贝构造
2.1.5 使用数组构造 vector int a1[] = { 1 ,2 ,3 ,4 }; vector<int > v1 (a1, a1 + 4 ) ;
2.2 析构函数 (destructor)
2.3 赋值重载 (operator=) vector& operator =(const vector& x);
2.4 迭代器 (iterator)
2.4.1 begin iterator begin () ; const_iterator begin () const ;
int a[] = { 1 ,2 ,3 }; vector<int > v1 (a,a+3 ) ; vector<int >::iterator it1 = v1. begin (); vector<int > v2 = { 2 ,3 ,4 }; vector<int >::iterator it2 = v2. begin (); const vector<int > v3 = { 3 ,4 ,5 }; vector<int >::const_iterator cit3 = v3. begin ();
2.4.2 end 获取 vector 最后一个数据的下一个位置的迭代器。
iterator end () ; const_iterator end () const ;
int a[] = { 1 ,2 ,3 }; vector<int > v1 (a,a+3 ) ; vector<int >::iterator eit1 = v1. end (); vector<int > v2 = { 2 ,3 ,4 }; vector<int >::iterator eit2 = v2. end ();
2.4.3 rbegin reverse_iterator rbegin () ; const_reverse_iterator rbegin () const ;
int a[] = { 1 ,2 ,3 }; vector<int > v1 (a,a+3 ) ; vector<int >::reverse_iterator rbit1 = v1. rbegin (); vector<int > v2 = { 2 ,3 ,4 }; vector<int >::reverse_iterator rbit2 = v2. rbegin ();
2.4.4 rend 获取 vector 第一个数据的前一个位置的迭代器。
reverse_iterator rend () ; const_reverse_iterator rend () const ;
int a[] = { 1 ,2 ,3 }; vector<int > v1 (a,a+3 ) ; vector<int >::reverse_iterator reit1 = v1. rend (); vector<int > v2 = { 2 ,3 ,4 }; vector<int >::reverse_iterator reit2 = v2. rend ();
2.4.5 迭代器总结 vector<int > v1 = { 1 ,2 ,3 ,4 ,5 }; vector<int >::iterator bit = v1. begin (); vector<int >::iterator eit = v1. end (); vector<int >::reverse_iterator rbit = v1. rbegin (); vector<int >::reverse_iterator reit = v1. rend ();
【注意】范围 for 只能正向遍历,无法反向遍历。
2.5 容量相关的成员函数 (capacity)
2.5.1 size vector<int > v1 (5 , 3 ) ; cout << v1. size () << endl;
2.5.2 max_size 返回 vector 能申请的最大空间的大小,但是是一个固定的值,且不同平台上值也可能会不同。
size_type max_size () const ;
vector<int > v; cout << v.max_size () << endl;
2.5.3 resize void resize (size_type n, value_type val = value_type()) ;
参数介绍:
n:新的 size 大小。
val:n 比原来的 size 大时,需要尾插的数据,默认为 0。
注:
n 小于当前 size 时,会直接将有效数据个数减少到 n。
当 n 大于当前 size,但小于当前 capacity 时,会尾插 val,直到 size 变成 n,val 如果不传,默认为 0。
当 n 大于当前 capacity 时,会先扩容,然后尾插 val,直到 size 变成 n。
2.5.4 capacity size_type capacity () const ;
vector<int > v; v.resize (12 );
2.5.5 reserve void reserve (size_type n) ;
注:当 n 小于当前 capacity 时,reserve 只会发出一个缩容的申请,但实际上并不会缩容,当 n 大于当前 capacity 时 reserve 会进行扩容。并且 reserve 全程不会对 size 有任何影响。
2.5.6 reserve 和 resize 的区别 reserve 只负责开空间 ,如果在明确知道需要多少空间的情况下使用 reserve 可以避免多次扩容的消耗。
resize 在开空间的情况下还会进行初始化 ,会影响 size。
vector 中 reserve 开出的空间无法使用 operator[] 等成员访问操作符进行访问,但 resize 开出的空间可以使用成员访问操作符进行访问和修改等操作 。
vector<int > v1; v1. resize (10 ); v1[5 ] = 4 ;
2.5.7 shrink_to_fit 缩小当前 capacity 到当前 size 大小。
vector<int > v; v.resize (10 );
注:shrink_to_fit 的操作一般是在异地开辟一块和当前 size 大小一样的空间,然后将旧数据拷贝到新的空间里,最后释放旧空间,是属于一种用时间换空间的方式。
2.6 访问操作相关的成员函数 (element access)
2.6.1 operator[] reference operator [](size_type n); const_reference operator [](size_type n) const ;
注:operator[] 在访问时会进行断言,只能访问在 size 以内的有效数据,如果 n 不在 [0,size) 这段区间内则会直接报错。但断言有个缺点,在 release 下不会起作用 。
vector<int > v{ 1 ,2 ,3 ,4 };
2.6.2 at reference at (size_type n) ; const_reference at (size_type n) const ;
vector<int > v{ 1 ,2 ,3 ,4 }; for (size_t i = 0 ; i < v.size (); i++) { cout << v.at (i) << " " ;
注:和 operator[] 不同的是,at 在访问时如果出现了越界访问的情况会直接抛出异常。
2.6.3 front reference front () ; const_reference front () const ;
vector<int > v1{ 1 ,2 ,3 ,4 }; cout << v1.f ront() << endl;
2.6.4 back reference back () ; const_reference back () const ;
vector<int > v{ 1 ,2 ,3 ,4 }; cout << v.back () << endl;
注:如果 vector 对象为空对象,那么使用 back 访问时会直接报断言错误。
2.7 修改相关的成员函数 (modifiers)
2.7.1 assign 使用一段迭代器区间覆盖当前对象的内容,或使用 n 个 val 覆盖当前对象里面的内容。
vector<int > v1{ 1 ,2 ,3 ,4 }; vector<int > v2{ 5 ,6 }; vector<int > v3{ 7 ,8 ,9 ,10 ,11 };
【注意】使用 assign 过程中旧数据会全部被新数据覆盖,size 和 capacity 都有可能会变化。
2.7.2 push_back void push_back (const value_type& val) ;
vector<int > v{ 1 ,2 ,3 ,4 }; cout << v.size () << endl;
2.7.3 pop_back vector<int > v{ 1 ,2 ,3 ,4 }; cout << v.size () << endl;
注:如果对象为空,使用 pop_back 时会报断言错误。
2.7.4 insert 在 position 位置之前插入一个 val,在 position 位置之前插入 n 个 val 或在 position 位置之前插入一段迭代器区间的数据。
在 vector 里面没有 find 这个函数,但在算法库 algorithm 里面有一个 find 函数,所有容器几乎都可以使用 。找不到会返回 last 位置的迭代器。但 string 里面还是需要自己设计单独的 find 函数,因为算法库里面的 find 无法支持 string 单独需要的查找字符串功能。
template <class InputIterator , class T > InputIterator find (InputIterator first, InputIterator last, const T& val) ;
vector<int > v1{ 1 ,2 ,3 ,4 ,5 }; vector<int > v2{ 5 ,6 ,7 }; vector<int >::iterator it = find (v1. begin (),v1. end (),3 );
注:单独插入一个 val 值时可以使用迭代器去接收返回后的迭代器,要插入的迭代器区间的一段内容时迭代器区间是左闭右开的,[first,last) 。
2.7.5 erase 删除 position 位置上的值、删除迭代器区间 [first,last) 的值。
vector<int > v1{ 1 ,2 ,3 ,4 ,5 ,6 }; vector<int >::iterator it = find (v1. begin (), v1. end (), 5 );
2.7.6 swap vector<int > v1{ 1 ,2 ,3 }; vector<int > v2{ 2 ,3 ,4 }; v1. swap (v2);
注:swap 交换会直接将成员变量的地址进行交换。
2.7.7 clear 清空 vector 内的所有元素,使 vector 的 size 变为 0。
vector<int > v1{ 1 ,2 ,3 ,4 }; cout << v1. size () << endl;
注:clear 只会清空 vector 内部的有效数据,但并不会销毁和释放 vector 申请的空间。
2.8 vector 迭代器失效问题 迭代器的主要作用就是让算法不用关心底层的数据结构,其底层实际上就是一个指针,或是对指针进行了封装。比如:vector 的迭代器就是原生指针 T 。因此迭代器失效实际上就是迭代器所指向的底层空间已经被销毁了,如果继续使用该迭代器去操作对应的底层空间,导致的后果就是程序崩溃。 *
对于 vector 可能会导致其迭代器失效的操作有:
1.会进行扩容的操作,都有可能会导致其迭代器失效 。例如:resize、reserve、insert、assign、push_back 等。
vector<int > v{ 1 ,2 ,3 ,4 ,5 }; cout << v.size () << endl;
reserve:当传入的 n 大于当前 capacity 时会进行扩容。
vector<int > v{ 1 ,2 ,3 ,4 ,5 }; cout << v.size () << endl;
insert:当插入元素时可能会出现空间不够进行扩容的情况。
vector<int > v{ 1 ,2 ,3 ,4 ,5 }; cout << v.size () << endl;
assign:assign 覆盖时如果新对象空间大于被覆盖对象的空间,那么被覆盖的对象就会进行扩容。
vector<int > v{ 1 ,2 ,3 ,4 ,5 }; cout << v.size () << endl;
push_back:尾插在空间不够的情况下也可能会进行扩容。
vector<int > v{ 1 ,2 ,3 ,4 ,5 }; cout << v.size () << endl;
2.指定位置的元素删除操作也可能会导致迭代器失效 。例如:erase。
erase 只是删除指定位置的数据,并不会导致空间的扩容,理论上来说迭代器不会失效,但如果 pos 刚好是 end 的前一个位置,且需要删除 end 前一个位置的数据,那么 erase 删除后 pos 的位置就和 end 的位置相同,此时 pos 迭代器就会失效。
vector<int > v{ 2 ,2 ,3 ,4 ,5 ,6 }; auto it = v.begin ();
如果将 v 拆分成{1,2,3}、{1,2,3,4,5}、{2,2,3,4,5}在 linux 平台 g++ 编译环境下会出现三种结果,分别是正常打印结果{1,3,5}、崩溃报错、错误打印结果{2,3,5}。
注:在这种情况下 erase 迭代器 it 指向的位置的值时,不仅结果出错,甚至程序都会崩溃。
上面代码的正确写法:在 erase 后需要重新使用 it 进行接收 erase 返回的迭代器。
vector<int > v{ 2 ,2 ,3 ,4 ,5 ,6 }; auto it = v.begin ();
总结:在 VS 平台下,编译器会认为 insert 和 erase 后的迭代器都会失效。解决办法:在使用迭代器之前重新对迭代器进行赋值,例如使用迭代器接收 insert 和 erase 的返回值 。
2.9 其他 vector 并没有设计流插入和流提取相关的函数,因为 vector 和 string 不同,string 打印时只需要打印字符串即可,但 vector 打印时可能会因为分隔符的原因出现不同的效果,分隔符需要使用者自己去设计,不同的使用者可能会有不同的设计风格,因此就没有提供流插入和流提取相关的函数。
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown 转 HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
HTML 转 Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online