天天看點

c++Primer——第九章:順序容器

1、幾個疊代器

begin、end、cbegin、cend、rbegin、rend、crbegin、crend

2、與順序容器大小相關的構造函數

順序容器(array除外)提供一個構造函數。它接受一個容器大小和一個(可選的)元素初始值,如果我們不提供元素的初始值,則标準庫會建立一個值初始化器。如果元素類型是沒有預設構造函數的類類型,則除了大小參數外,還必須指定一個顯式的元素初始值。

3、标準庫array

使用array必須同時指定元素類型和大小

array<int, 3> arr;	//3個預設初始化的int
	array<int> arr1;	//錯誤  沒有array<int>類型
	array<int, 3> arr2 = { 1,2,3 }; //清單初始化
	array<int, 3> arr3 = { 1 }; // 1,0,0
           

内置數組不能進行拷貝或對象指派,但标準庫array支援這種操作

int a[3] = { 1,2,3 };
	int b[3] = a;		//錯誤 内置數組不支援拷貝或指派
	array<int, 3> c = { 1,2,3 };
	array<int, 3> d = c; //正确
           

4、指派和swap

指派相關運算會導緻指向左邊容器内部的疊代器、引用、指針失效。而swap操作不會使他們失效。

5、assign

指派運算符要求左右兩邊的運算對象具有相同的類型。順序容器(除了array)還定義了一個名為assign的成員,允許我們從一個不同但相容的類型指派,或者從一個容器的子序列指派。assign也是拷貝

list<string> sl;
	vector<const char*> cv;
	sl = cv;  // 錯誤 容器類型不比對
	sl.assign(cv.begin(), cv.end()); //正确
	//也可以這樣用
	sl.assign(10, "hi");
           

6、swap

swap操作交換兩個相同類型的容器的内容。除array外,swap不對任何元素進行拷貝、删除或插入操作,是以可以保證在常數時間内完成。元素不會被移動的事實意味着除了string外,指向容器的疊代器、引用、指針在swap操作之後都不會失效,他們仍然指向swap交換前的元素,但是,着些元素已經屬于不同的容器了。

7、emplace操作

emplace_fron、emplace、emplace_back是c++11新标準引入的成員,他們操作構造而不是拷貝元素。使用push或insert時是将元素類型的對象傳遞給它們,這些對象被拷貝到容器中,而調用emplace成員時,則是将參數傳遞給元素類型的構造函數

class A
{
public:
	A(int x, int y):a(x), b(y){}
	~A(){}

private:
	int a;
	int b;
};

void test()
{
	vector<A> vec;
	vec.emplace_back(1, 2);
	vec.push_back(A(1, 2));
}
           

10、通路元素

  • 包括array在内的每個順序容器都有一個front成員函數
  • 除forward_list之外的所有順序容器都有一個back成員函數
  • at和下标操作隻适用于string、vector、deque和array

以上操作使用前都需要確定容器非空,它們都傳回元素的引用。非const得情況下可以當左值使用。

11、下标操作和安全的随機通路

下标運算符并不檢查下标是否在合法的範圍内,使用越界的下标是一種嚴重的程式設計錯誤,編譯器不檢查這種錯誤。如果我們希望確定下标是合法的。可以使用at成員函數,使用at下标越界時會抛出out_of_range異常

vector<int> vec;
	cout << vec[0] << endl; //運作時錯誤 vec中沒元素
	cout << vec.at(0) << endl; // 抛出out_of_range異常
           

12、resize和reserve

vector<int> ivec{ 5,3 };
	ivec.resize(10); //前5個3 後5個0
	cout << ivec.size() << " " << ivec.capacity() << endl;  // 10 10
	ivec.resize(3);	 //删除末尾的7個值  capacity不變
	cout << ivec.size() << " " << ivec.capacity() << endl;  // 3 10
	ivec.reserve(1);
	cout << ivec.size() << " " << ivec.capacity() << endl;  // 3 10
	ivec.reserve(8);
	cout << ivec.size() << " " << ivec.capacity() << endl;  // 3 10
	ivec.erase(ivec.begin());
	cout << ivec.size() << " " << ivec.capacity() << endl;  // 2 10
	ivec.shrink_to_fit();
	cout << ivec.size() << " " << ivec.capacity() << endl;  // 2 2
           

shrink_to_fit也隻是個請求,标準庫并不保證一定退還記憶體

13、string的諸多操作

14、容器擴充卡

标準庫定義了三個順序容器擴充卡:stack、queue和priority_queue

一個容器擴充卡接受一種已有的容器類型。使其行為看起來像一種不同的類型

預設情況下stack和queue是deque實作的,priority_queue是在vector上實作的。我們可以在建立一個擴充卡時将一個命名的順序容器作為第二個類型參數來重載預設容器類型

stack<string, vector<string>> str_stk; //在vector上實作的空棧
	stack<string, vector<string>> str_stk2(svec); //在vector上實作的棧,初始化時儲存svec的拷貝
           

stack隻要求push_back、pop_back、back操作,是以可以使用除array和forward_list外的任何容器類型來構造。queue要求back、push_back、front、push_front,是以可以構造與list或dqueu之上,但不能基于vector構造。priority_queue除了front、push_back、pop_back外還要求随機通路能力,是以可以用vector和deque構造,不能用list

繼續閱讀