C++ vector的使用、建立及初始化

2020-07-16 10:04:27
vector<T> 容器是包含 T 型別元素的序列容器,和 array<T,N> 容器相似,不同的是 vector<T> 容器的大小可以自動增長,從而可以包含任意數量的元素;因此型別引數 T 不再需要模板引數 N。只要元素個數超出 vector 當前容量,就會自動分配更多的空間。只能在容器尾部高效地刪除或新增元素。

vector<T> 容器可以方便、靈活地代替陣列。在大多數時候,都可以用 vector<T> 代替陣列存放元素。只要能夠意識到,vector<T> 在擴充套件容量,以 及在序列內部刪除或新增元素時會產生一些開銷;但大多數情況下,程式碼不會明顯變慢。 為了使用 vector<T> 容器模板,需要在程式碼中包含標頭檔案 vector。

建立vector<T>容器

下面是一個生成存放 double 型元素的 vector<T> 容器範例:
std::vector<double> values;
因為容器中沒有元素,所以沒有分配空間,當新增第一個資料項時,會自動分配記憶體。可以像下面這樣通過呼叫 reserve() 來增加容器的容量:
values.reserve(20);
這樣就設定了容器的記憶體分配,至少可以容納 20 個元素。如果當前的容量已經大於或等於 20 個元素,那麼這條語句什麼也不做。注意,呼叫 reserve() 並不會生成任何元素。values 容器這時仍然沒有任何元素,直到新增了 20 個元素後,才會分配更多的記憶體。呼叫 reserve() 並不會影響現有的元素。

當然,如果通過呼叫 reserve() 來增加記憶體,任何現有的疊代器,例如開始疊代器和結束疊代器,都會失效,所以需要重新生成它們。這是因為,為了增加容器的容量,vector<T> 容器的元素可能已經被複製或移到了新的記憶體地址。

建立 vector 容器的另一種方式是使用初始化列表來指定初始值以及元素個數:
std::vector<unsigned int> primes {2u, 3u, 5u, 7u, 11u, 13u, 17u, 19u};
以初始化列表中的値作為元素初始值,生成有 8 個素數的 vector 容器。

分配記憶體是比較花費時間的,所以最好只在必要時分配。vector 使用演算法來增加容量,這個演算法依賴一個經常使用的常對數來實現,這在早些時候會導致分配一些非常小的記憶體,但是隨著 vector 容量的增大,記憶體增長數也會變大。可以如下所示,使用初始元素個數來生成 vector 容器:
std::vector<double> values(20);
這個容器開始時有 20 個元素,它們的預設初始值都為 0。生成容器時,同時指定元素個數,就能夠減少空間額外分配的次數,這是一個很好的習慣。

注意,圓括號中的 20 表示元素的個數,是上述語句的核心。這裡不能使用 {}。如果如下所示定義 vector 容器,會產生不同的結果:
std::vector<double> values {20};
vector 並沒有 20 個元素。它只有一個元素,並以 20 作為初始值。新增元素會導致分配額外的記憶體。

如果不想用 0 作為預設值,可以指定一個其他值:
std::vector<long> numbers(20, 99L);
第二個引數指定了所有元素的初始值,因此這 20 個元素的值都是 99L。第一個元素指定了 vector 中的元素個數,它不需要是一個常數表示式。它可以是一個表示式執行後的結果,也可以是從鍵盤輸入的數。

可以用元素類印相同的容器來初始化 vector<T> 容器。用一對疊代器來指定初始值的範圍。下面是一個範例:
std::array<std :: string, 5> words {"one", "two","three", "four", "five"};
std::vector<std::string> words_copy {std::begin(words) , std::end(words)};
words_copy 被 words 陣列容器中的元素初始化。如果使用移動迭代器指定 words_copy 的初始化範圍,words 中的元素將會從 words 移到 words_copy。這裡有一個範例:
std::vector<std::string〉 words_copy {std::make_move_iterator(std::begin(words)),std::make_move_iterator(std:: end(words))};
words_copy 會像前面那樣被初始化。但元素是移動過來的而不是複製過來的,所以 words 陣列中的字串物件現在都是空字串。