【C++/STL】vector基本介绍
vector的介绍及使用
介绍
1.vector表示可变大小数组的序列容器。
2.vector像数组一样采用连续的存储空间来存储数据,意味着可以采用下标对vector的元素进行访问。它的大小可以动态改变且会被容器自动处理。
3.vector的底层实现采用动态分配数组内存来存储它的元素。当新元素插入时,可能需要重新分配并增加存储空间。做法为:分配一个新的数组,然后将全部元素移到这个数组中,时间开销较大,所以当容器中添加新元素时,vector并不会每次都重新分配大小。
4.分配策略为:vector会额外分配一些空间以适应可能的增长。不同的库采用不同的策略来权衡空间的使用和重新分配。
5.与其他容器相比,vector在访问元素时更高效,在末尾删除或添加元素时更高效。
使用
vector的文档介绍
以下是需要重点掌握的接口:
vector的定义
1.vector() 无参构造
2.vector(size_type n, const value_type& val = value_type()) 构造并初始化n个val
3. vector(const vector& x) 拷贝构造
4. vector(InputIterator first,InputIterator last) 使用迭代器进行初始化构造
vector iterator的使用
1.begin+end
获取第一个数据位置或最后一个数据的下一个位置iterator/const_iterator
(迭代器区间为左闭右开)
2.rbegin+rend
获取最后一个数据位置或第一个数据的前一个位置reverset_iterator
vector空间增长问题
resize reserve
vs下capacity是按1.5倍增长的,g++是按2倍增长的。vs是PJ版本STL,g++是SGI版本STL。reserve只负责开辟空间,确定知道要用多少空间时更高效。resize在开空间的同时会进行初始化,影响size。
//在两种环境下测试vector的默认扩容机制
若已知大概空间大小,用reserve提高效率
vector增删查改
vector迭代器失效问题(重难点)
迭代器的主要作用是让算法能不用关心底层数据结构,迭代器底层实际就是一个指针,或者说是对指针进行了封装。 vector的迭代器就是原生态指针T*,则迭代器失效实际就是迭代器底层对应指针所指向的空间被销毁了,而是用一块已经被释放的空间,造成的后果就是程序崩溃(若继续使用已经失效的迭代器,程序可能会崩溃)。
vector可能会导致其迭代器失效的操作有:
1.会引起其底层空间改变的操作(如扩容),都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back等.
int main()
{vector<int> v{ 2,4,6,8,9,5 };vector<int>::iterator it = v.begin();v.resize(100, 6);v.reserve(150);v.insert(v.begin(), 0);v.push_back(8);v.assign(100, 7);return 0;
}
扩容会使旧空间被释放掉,而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。
解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新
赋值即可。
2.指定位置元素的删除操作–erase
erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。
3. Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端。
比如:
以上程序可正常运行:
erase删除的迭代器如果是最后一个元素,删除之后it已经超过end,此时迭代器是无效的,++it导致程序崩溃。
从上述例子中可以看到:SGI STL中,迭代器失效后,代码并不一定会崩溃,但是运行结果肯定不
对,如果it不在begin和end范围内,一定会崩溃。
4. 与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效。
#include <string>
void TestString()
{string s("hello");auto it = s.begin();// 放开之后代码会崩溃,因为resize到20会string会进行扩容// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了// 后序打印时,再访问it指向的空间程序就会崩溃//s.resize(20, '!');while (it != s.end()){cout << *it;++it;}cout << endl;it = s.begin();while (it != s.end()){it = s.erase(it);// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后// it位置的迭代器就失效了// s.erase(it); //++it;}
}
erase会自动返回下一个有效迭代器。
迭代器失效解决办法:在使用前,对迭代器重新赋值。