6.1 容器的共通能力和共通操作
所有容器提供的都是value語意而非reference語意。容器元素必須能夠被拷貝。
總體而言,所有元素形成一個次序。運用迭代器遍歷,也是算法的基礎。
各項操作並非安全,調用者必須確保參數符合要求。違反可能導致未定義行爲。通常STL自身不拋出異常。
初始化:每個容器提供了一個默認構造函數、copy構造函數、析構函數。
容器類別的共通函數:
C c; 不含任何元素的空容器
C c(c1); 產生一個同型容器
C c(beg, end); 複製區間元素,作爲容器初值
c.~C(); 刪除所有元素,釋放內存
c.size(); 返回容器元素數量
c.empty(); 若容器爲空返回true
c.max_size(); 返回容器內元素最大可能數量
c1 == c2 ;
c1 != c2 ; > < >= <=
c1 = c2; 將c2的所有元素賦值給c1
c1.swap(c2); 交換c1和c2的數據
swap(c1, c2); 同上,全局函數
c.begin(); 返回指向第一個元素迭代器
c.end(); 返回指向最後元素的下個位置的迭代器
c.rbegin(); 返回指向逆向遍歷時候的第一個元素的逆向迭代器
c.rend(); 返回指向逆向遍歷時候的最後元素的下個位置的逆向迭代器
c.insert(pos, elem); 將elem的一份副本插入pos處,返回值和pos意義並不同
c.erase(beg, end); 移除區間內所有元素
c.clear(); 移除所有元素
c.get_allocator(); 返回容器的內存模型
以另一個容器的元素爲初值完成初始化:
list<int> l;
vector<float> c(l.begin(), l.end());
以某個數組元素爲初始初始化:
int a[] = { 2, 3, 17, 33, 45, 77 };
set<int> c(a, a + sizeof(a)/sizeof(*a));
標準輸入完成初始化:
deque<int> c((istream_iterator<int>(cin)),(istream_iterator<int>())); //括號不能少,否則視爲c爲一個函數聲明
6.2 vector : 動態數組
#include <vector>
具備assignable 和 copyable兩個性質
namespace std {
template <class T, class Allocator = allocator<T> >
class vector;
}
//第二個參數一般省略,缺省是C++ STL提供的allocator分配器
vector是有序羣集,支持隨機存取,隨機存取迭代器,任何STL算法都適用。
末端附加和刪除元素時候,性能好。前端或中間插入和刪除元素性能不好。因爲要移動操作點之後的所有元素,這是很多 = 賦值操作符。
capacity(); 返回vector實際能容納的元素數量,如果超越這個數量vector就會重新配置內部存儲器。
一旦內存重新配置,和vector元素有關的所有reference、pointers、iterator都會失效,內存重新配置很耗時間。
可以使用reserve()函數保留適當容量,只能增不能減,避免總是重新配置內存,避免iterator失效。 vector<int> v; v.reserve(80); 分配了80個元素的v
還可以在構造期間分配大小: vector<int> v(100); //v 起始大小100個元素
構造和析構函數:
vector<Elem> c;
vector<Elem> c1(c2);
vector<Elem> c(n);
vector<Elem> c(n, elem);
vector<Elem> c(beg, end);
c.~vector<Elem>();
非變動性操作:
c.size();
c.empty();
c.max_size();
capacity();
reserve(n);
c1 == c2; != < > <= >=
賦值:
c1 = c2;
c.assign(n, elem);
c.assign(beg, end);
c1.swap(c2);
swap(c1, c2);
元素存取:index 從0到size()-1; 對於non-const vector返回元素的reference;程序員自己檢查範圍例如是否爲空;
c.at(idx); //out_of_range 異常
c[idx]; 不進行範圍檢查
c.front();
c.back();
迭代器相關:其實就是個指針,vector內部結構是數組
c.begin(); //隨機存取迭代器
c.end();
c.rbegin(); //逆向迭代器
c.rend();
迭代器失效情況:較小的索引位置插入或移除元素;容量變化重新引起內存分配
插入和移除元素使作用點之後的元素迭代器失效,甚至引發內存重新分配屆時所有迭代器失效;
移除插入相關操作:
c.insert(pos, elem); //返回新元素位置
c.insert(pos, n, elem); //無返回值
c.insert(pos, beg, end); //無返回值
c.push_back(elem);
c.pop_back();
c.erase(pos); //返回下一個元素的位置
c.erase(beg, end); //返回下一個元素的位置
c.resize(num); 將元素數量改爲num,如果size()增大了,多出新元素需要默認構造函數完成
c.resize(num, elem);
c.clear(); 容器清空
vector<Elem> c;
c.erase(remove(c.begin(), c.end(), val), c.end()); //將所有其值爲val的元素移除
#include <algorithm>
#include <vector>
#include <iostream>
#include "print.cpp"
using namespace std;
int main()
{
int a[] = {3, 4, 5, 3, 7, 9, 3, 4};
vector<int> v(a, a+sizeof(a)/sizeof(*a));
v.erase(remove(v.begin(), v.end(), 3), v.end());
print_elements(v, "after erase: "); //4 5 7 9 4
return 0;
}
若想移除與某值相等的第一個元素:
#include <algorithm>
#include <vector>
#include <iostream>
#include "print.cpp"
using namespace std;
int main()
{
int a[] = {3, 4, 5, 3, 7, 9, 3, 4};
vector<int> v(a, a+sizeof(a)/sizeof(*a));
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
if(pos != v.end())
{
v.erase(pos);
}
print_elements(v, "after erase: "); //4 5 3 7 9 3 4
return 0;
}
將vector當作一般array使用:
&v[i] = &v[0] + i;
vector<char> v;
v.resize(40);
strcpy(&v[0], "hello, world");
printf("%s\n", &v[0]); //printf("%s\n", v.begin()); is error
異常處理:
下標操作的安全版本:at()
push_back()安插元素時候發生異常,插入不起作用
若元素拷貝不拋出異常,insert要麼成功要麼不生效
pop_back()不拋異常
若拷貝操作不拋異常,erase()和clear()不拋異常
swap()不拋異常
若拷貝操作絕對不拋異常,那麼所有操作要麼成功要麼不起作用。
析構函數不拋異常
一個例子總結vector:
#include <algorithm>
#include <vector>
#include <iostream>
#include "print.cpp"
#include <string>
using namespace std;
int main()
{
vector<string> s;
s.reserve(5);
s.push_back("Hello, ");
s.push_back("how ");
s.push_back("are ");
s.push_back("you ");
s.push_back("?");
print_elements(s, "init: "); //init: Hello, how are you ?
cout << "max_size(): " << s.max_size() << endl; //1073741823
cout << "size(): " << s.size() << endl; //5
cout << "capacity(): " << s.capacity() << endl; //5
swap(s[1], s[3]);
s.insert(find(s.begin(), s.end(), "?"), "always");
s.back() = "!";
print_elements(s, "after: "); //after: Hello, you are how always !
cout << "max_size(): " << s.max_size() << endl; //1073741823
cout << "size(): " << s.size() << endl; //6
cout << "capacity(): " << s.capacity() << endl; //10
return 0;
}