vector:
vector是表示可变大小数组的序列容器。即动态顺序表。
就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
相关接口:
构造函数:
- vector() 无参构造
- vector(size_type n, const value_type& val = value_type()) 构造并初始化n个val
- vector (const vector& x); 拷贝构造
- vector (InputIterator first, InputIterator last); 使用迭代器进行初始化构造
迭代器:
- iterator的使用 接口说明
- begin() 获取第一个数据位置的iterator
- end() 获取最后一个数据的下一个位置的iterator
- rbegin() 获取最后一个数据位置的reverse_iterator
- rend() 获取第一个数据前一个位置的reverse_iterator
- cbegin() 获取第一个数据位置的const_iterator
- cend() 获取最后一个数据的下一个位置的const_iterator
容量空间: 每次扩容50%
- size() 获取数据个数
- capacity() 获取容量大小
- empty() 判断是否为空
- void resize (size_type n, value_type val = value_type()); 改变vector的size
- void reserve (size_type n); 改变vector放入capacity
vector增删查改:
- void push_back (const value_type& val); 尾插
- void pop_back(); 尾删
- InputIterator find (InputIterator first, InputIterator last, const T& val); 查找。(注意这个是算法模块实现,不是 vector的成员接口)
- iterator insert (iterator position, const value_type& val); 在position之前插入val
- iterator erase (iterator position); 删除position位置的数据
- void swap (vector& x); 交换两个vector的数据空间
- reference operator[] (size_type n); 像数组一样访问
vector 迭代器失效问题:也是push_back()的缺陷
两层含义:
1. 无法通过迭代器++,--操作遍历整个stl容器。记作:第一层失效。
2. 无法通过迭代器存取迭代器所指向的内存。 记作:第二层失效。
vector迭代器的几种失效的情况: push_back()的缺陷:
- 当插入(push_back)一个元素后,end操作返回的迭代器肯定失效。
- 当插入(push_back)一个元素后,capacity返回值与没有插入元素之前相比有改变,则需要重新加载整个容器,此时first和end操作返回的迭代器都会失效。
- 当进行删除操作(erase,pop_back)后,指向删除点的迭代器全部失效;指向删除点后面的元素的迭代器也将全部失效。
insert/erase导致的迭代器失效:
// insert/erase导致的迭代器失效
#include <iostream>
#include <algorithm>
#include <vector> using namespace std;
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; // 此处会导致非法访问
// 在pos位置插入数据,导致pos迭代器失效。
// insert会导致迭代器失效,是因为insert可
// 能会导致增容,增容后pos还指向原来的空间,而原来的空间已经释放了。
pos = find(v.begin(), v.end(), 3);
v.insert(pos, 30);
cout << *pos << endl; // 此处会导致非法访问
return 0;
}
vetor使用了连续分配的内存,安插操作时:
- 容器还有一定的容量(v.capacity())来容纳这个元素。如此一来,安插和移除操作不会因容器满而重新分配内存。在安插和移除操作后,作用点位置前的元素并没改变,而操作位置后的元素向后或向前移动一位。
- 插入元素后当发现开辟的空间不够了,就会开辟更大的空间来进行拷贝数据,这个时候原来的start、finish、endofstorage都会发生变化,所以要插入位置已经变化,而传过来的位置还是原来的位置,就会出现插入越界。
删除操作时:
erase迭代器失效是在删除一个元素的时候,后面的元素要向前挪动,所以迭代器指向的位置就会被前面的覆盖,这时候++迭代器,就会跳过删除元素的后一个。
解决迭代器失效方法:
删除解决:<此部分代码来源网络>
for (iter = cont.begin(); iter != cont.end();)
{
(*it)->doSomething();
if (shouldDelete(*iter))
iter = cont.erase(iter); //erase删除元素,返回下一个迭代器
else
++iter;
}
erase方法可以返回下一个有效的iterator。这样删除后iter指向的元素后,返回的是下一个元素的迭代器,这个迭代器是vector内存调整过后新的有效的迭代器。
插入处理:<此部分代码来源网络>
我们在插入前计算出相对与start的相对距离,那么当插入时候我们用计算的距离还原pos进行插入。
Iterator Insert(Iterator position, const T& value)
{
assert(position < End() && position >= Begin());
size_t off = position - start;
if (finish == endofstorage)
{
Expand(Capacity() * 2);
}
position = off + start; // 注意跌掉器失效
for (Iterator i = End(); i != position; --i)
{
*i = *(i - 1);
}
*position = value;
++finish;
return position;
}