C++11 中引進了一種叫 List Initializing 的技術,C++ Primer 5th 的 3.3.1. Defining and Initializing vectors 中很是膚淺的介紹了一下它的形式:ios
cppvector<string> articles = {"a", "an", "the"}; // or vector<string> articles{"a", "an", "the"};
書中頗爲推崇這樣的初始化方式,且形式上更加貼近 C 語言中 array 的初始化過程,非常親民。c++
但咱們簡單作個實驗,來講明這種形式在效率上可能存在的問題:函數
cpp#include <iostream> #include <vector> struct X { X() { std::cout << "X()" << std::endl; } X(const X&) { std::cout << "X(const X&)" << std::endl; } // copy constructor ~X() { std::cout << "~X()" << std::endl; } } int main() { X x; std::vector<X> vec{x, x}; }
猜猜看,這段程序的輸出是什麼?ui
X() X(const X&) X(const X&) X(const X&) X(const X&) ~X() ~X() ~X() ~X() ~X()
看看有沒有猜對呢?c++11
有沒有人好奇,爲何 copy constructor 被調用了四次? 咱們但願它被調用多少次呢?很顯然,是兩次。code
咱們對 main 函數稍做修改:對象
cppint main() { X x; std::vector<X> vec; vec.reserve(2); vec.push_back(x); vec.push_back(x); }
而後查看本次輸出:get
X() X(const X&) X(const X&) ~X() ~X() ~X()
的確變成了咱們但願的兩次。若是有興趣的話,能夠將 reserve
那句話給註釋掉試試,會發現調用次數變成了3次,但那不屬於我們本次探討的範疇,若是有疑問能夠留言討論。string
第二次雖然多寫了幾行,但貌似極大程度上的避免了 copy constructor 的頻繁調用,想象一下若初始化列表裏躺着一大堆 x 會有什麼下場。it
揭祕
copy constructor 的調用次數爲什麼會翻倍?
由於 List Initializing 本質上是先基於列表中的元素,構造出一個 initializer_list
, 這個類型也是 c++11 引入的,能夠看看詳細定義。
而後,再將構造出來的 initializer_list
中的元素逐一 copy 至容器中。
故:
cppstd::vector<X> vec{x, x};
至關於:
cppstd::initializer_list<X> list = {x, x}; // copy 2 times std::vector<X> vec(list); // copy 2 times
真相大白。
結論
對於非 built-in 對象來講, 使用 List Initializing 付出的代價,在某些狀況下不容忽視。 過去陳舊的寫法,反而讓人更加踏實。