先点赞后观看哦!!!谢谢大家!
1.vector的使用说明
1.1vector的介绍
http://www.cplusplus.com/reference/vector/vector/
使用 STL 的三个境界:能用,明理,能扩展 ,那么学习 vector ,我们也是按照这个方法去学
习。
1.2vector的使用
1.2.1vector的定义

1.2.2vector literator的使用


1.2.3vector空间增长问题

1.capacity 的代码在 vs 和 g++ 下分别运行会发现, vs 下 capacity 是按 1.5 倍增长的, g++ 是按 2
倍增长的 。这个问题经常会考察,不要固化的认为, vector 增容都是 2 倍,具体增长多少是
根据具体的需求定义的。 vs 是 PJ 版本 STL , g++ 是 SGI 版本 STL 。
2.reserve 只负责开辟空间,如果确定知道需要用多少空间, reserve 可以缓解 vector 增容的代
价缺陷问题。
3.resize 在开空间的同时还会进行初始化,影响 size 。
// 如果已经确定 vector 中要存储元素大概个数,可以提前将空间设置足够
// 就可以避免边插入边扩容导致效率低下的问题了
void TestVectorExpandOP ()
{
vector < int > v ;
size_t sz = v . capacity ();
v . reserve ( 100 ); // 提前将容量设置好,可以避免一遍插入一遍扩容
cout << "making bar grow:\n" ;
for ( int i = 0 ; i < 100 ; ++ i )
{
v . push_back ( i );
if ( sz != v . capacity ())
{
sz = v . capacity ();
cout << "capacity changed: " << sz << '\n' ;
}
}
}
1.2.3vector增删改查

1.2.4vector迭代器失效问题(重点)
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对
指针进行了封装 ,比如: vector 的迭代器就是原生态指针 T* 。因此 迭代器失效,实际就是迭代器
底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间 ,造成的后果是程序崩溃 ( 即
如果继续使用已经失效的迭代器,程序可能会崩溃 ) 。
对于 vector 可能会导致其迭代器失效的操作有:
- 会引起其底层空间改变的操作,都有可能是迭代器失效 ,比如: resize 、 reserve 、 insert 、
assign 、 push_back 等。
#include <iostream>
using namespace std ;
#include <vector>
int main ()
{
vector < int > v { 1 , 2 , 3 , 4 , 5 , 6 };
auto it = v . begin ();
// 将有效元素个数增加到 100 个,多出的位置使用 8 填充,操作期间底层会扩容
// v.resize(100, 8);
// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容
量改变
// v.reserve(100);
// 插入元素期间,可能会引起扩容,而导致原空间被释放
// v.insert(v.begin(), 0);
// v.push_back(8);
// 给 vector 重新赋值,可能会引起底层容量改变
v . assign ( 100 , 8 );
/*
出错原因:以上操作,都有可能会导致vector 扩容,也就是说 vector 底层原理旧空间被释
放掉,而在打印时,it 还使用的是释放之间的旧空间,在对 it迭代器操作时,实际操作的是
一块已经被释放的空间,而引起代码运行时崩溃。
解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector 中的元素,只需给
it重新赋值即可。
*/
while ( it != v . end ())
{
cout << * it << " " ;
++ it ;
}
cout << endl ;
return 0 ;
} - 指定位置元素的删除操作 - -erase、
int main ()
{
int a [] = { 1 , 2 , 3 , 4 };
vector < int > v ( a , a + sizeof ( a ) / sizeof ( int ));
// 使用 find 查找 3 所在位置的 iterator
vector < int > :: iterator pos = find ( v . begin (), v . end (), 3 );
// 删除 pos 位置的数据,导致 pos 迭代器失效。
v . erase ( pos );
cout << * pos << endl ; // 此处会导致非法访问
return 0 ;
}
erase 删除 pos 位置元素后, pos 位置之后的元素会往前搬移,没有导致底层空间的改变,理
论上讲迭代器不应该会失效,但是:如果 pos 刚好是最后一个元素,删完之后 pos 刚好是 end
的位置,而 end 位置是没有元素的,那么 pos 就失效了。因此删除 vector 中任意位置上元素
时, vs 就认为该位置迭代器失效了。
以下代码的功能是删除 vector 中所有的偶数,请问那个代码是正确的,为什么?
int main ()
{
vector < int > v { 1 , 2 , 3 , 4 };
auto it = v . begin ();
while ( it != v . end ())
{
if ( * it % 2 == 0 )
v . erase ( it );
++ it ;
}
return 0 ;
}
int main ()
{
vector < int > v { 1 , 2 , 3 , 4 };
auto it = v . begin ();
while ( it != v . end ())
{
if ( * it % 2 == 0 )
it = v . erase ( it );
else
++ it ;
}
return 0 ;
} - 注意: Linux 下, g++ 编译器对迭代器失效的检测并不是非常严格,处理也没有 vs 下极端。
// 1. 扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
int main ()
{
vector < int > v { 1 , 2 , 3 , 4 , 5 };
for ( size_t i = 0 ; i < v . size (); ++ i )
cout << v [ i ] << " " ;
cout << endl ;
auto it = v . begin ();
cout << " 扩容之前, vector 的容量为 : " << v . capacity () << endl ;
// 通过 reserve 将底层空间设置为 100 ,目的是为了让 vector 的迭代器失效
v . reserve ( 100 );
cout << " 扩容之后, vector 的容量为 : " << v . capacity () << endl ;
// 经过上述 reserve 之后, it 迭代器肯定会失效,在 vs 下程序就直接崩溃了,但是 linux
下不会
// 虽然可能运行,但是输出的结果是不对的
while ( it != v . end ())
{
cout << * it << " " ;
++ it ;
}
cout << endl ;
return 0 ;
}
程序输出:
1 2 3 4 5
扩容之前, vector 的容量为 : 5
扩容之后, vector 的容量为 : 100
0 2 3 4 5 409 1 2 3 4 5
// 2. erase 删除任意位置代码后, linux 下迭代器并没有失效
// 因为空间还是原来的空间,后序元素往前搬移了, it 的位置还是有效的
#include <vector>
#include <algorithm>
int main ()
{
vector < int > v { 1 , 2 , 3 , 4 , 5 };
vector < int > :: iterator it = find ( v . begin (), v . end (), 3 );
v . erase ( it );
cout << * it << endl ;
while ( it != v . end ())
{
cout << * it << " " ;
++ it ;
}
cout << endl ;
return 0 ;
}
程序可以正常运行,并打印:
4
4 5
// 3: erase 删除的迭代器如果是最后一个元素,删除之后 it 已经超过 end
// 此时迭代器是无效的, ++it 导致程序崩溃
int main ()
{
vector < int > v { 1 , 2 , 3 , 4 , 5 };
// vector<int> v{1,2,3,4,5,6};
auto it = v . begin ();
while ( it != v . end ())
{
if ( * it % 2 == 0 )
v . erase ( it );
++ it ;
}
for ( auto e : v )
cout << e << " " ;
cout << endl ;
return 0 ;
}
========================================================
// 使用第一组数据时,程序可以运行
sly@VM - 0 - 3 - centos 20220114 \] $ g ++ testVector . cpp - std = c ++ 11
\[ sly@VM - 0 - 3 - centos 20220114 \] $ . / a . out
1 3 5
=========================================================
// 使用第二组数据时,程序最终会崩溃
\[ sly@VM - 0 - 3 - centos 20220114 \] $ vim testVector . cpp
\[ sly@VM - 0 - 3 - centos 20220114 \] $ g ++ testVector . cpp - std = c ++ 11
\[ sly@VM - 0 - 3 - centos 20220114 \] $ . / a . out
Segmentation fault
从上述三个例子中可以看到: SGI STL 中,迭代器失效后,代码并不一定会崩溃,但是运行
结果肯定不对,如果 it 不在 begin 和 end 范围内,肯定会崩溃的。
4. 与 vector 类似, string 在插入 + 扩容操作 +erase 之后,迭代器也会失效
#include \
