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;
}