轉載請註明文章出處:https://tlanyan.me/reserve-of...
vector
是C++
編程時的常用容器,其幫助用戶自動管理存儲空間,簡單易用,且能避免資源泄露的問題。需要動態分配存儲空間的場景,完全可替代原生數組。
vector
被人詬病的地方在於性能。C++ 11
引入array
容器,有原生數組的性能,編譯期能確定大小的情況可取代vector
。但對於運行期才能確定大小的情況,array
不適用,還是得上vector
。
實踐中提高vector
性能的要點是儘量使用reserve(僅次於換編譯器和STL實現)。運行期依然不能確定數組的個數,明智的選擇是什麼也不做,push_back/emplace_back
就足夠;運行期能確定個數,則應該用reserve
,不建議用傳遞大小的數組構造函數或者調用resize
。
reserve
vs resize
reserve
和resize
函數都能分配足夠容納下指定個數對象的空間。不同之處是resize
(或構造函數傳遞數組個數)會改變數組的size
(即當前元素的指針),並且極大的可能性會調用存儲對象的(複製)構造函數。reserve
做的事情就比較純粹:僅分配所需的空間。
一段代碼說明三者的區別:
// file: test.cpp
#include <iostream>
#include <vector>
class Foo {
public:
Foo() {
std::cout << "Foo constructor" << std::endl;
}
};
int main(int argc, char* argv[]) {
std::cout << "initialize vector with element number..." << std::endl;
std::vector<Foo> vec1(5);
std::cout << "-------------" << std::endl;
std::cout << "vec1 size:" << vec1.size() << std::endl << std::endl;
std::cout << "vector resize..." << std::endl;
std::vector<Foo> vec2;
vec2.resize(5);
std::cout << "-------------" << std::endl;
std::cout << "vec2 size:" << vec2.size() << std::endl << std::endl;
std::cout << "vector reserve..." << std::endl;
std::vector<Foo> vec3;
vec3.reserve(5);
std::cout << "-------------" << std::endl;
std::cout << "vec3 size:" << vec3.size() << std::endl << std::endl;
return 0;
}
用gcc
編譯程序:g++ -std=c++0x -o test -O2 test.cpp
,然後./test
執行程序,結果如下:
initialize vector with element number...
Foo constructor
Foo constructor
Foo constructor
Foo constructor
Foo constructor
-------------
vec1 size:5
vector resize...
Foo constructor
Foo constructor
Foo constructor
Foo constructor
Foo constructor
-------------
vec2 size:5
vector reserve...
-------------
vec3 size:0
輸出結果很顯然:無論用構造數組時指定個數,還是resize
,都會調用存儲類型的默認構造函數並改變size
。常規情況下,默認生成的對象沒什麼用處,最後都會被覆蓋掉。如果存儲類型的構造函數比較複雜,這兩種方式都以大代價做無用功。
而reserve
就不會,理念簡單,性能槓槓的。
注意:編譯上述程序,去掉-std=c++0x
選項,結果將會不同。原因是vector
的構造函數或者resize
默認用複製的方式填充,所以構造函數僅調用一次。
總結
細心對比,你會發現reserve
和resize
的區別就像malloc
和new
的區別(不過malloc
是函數,new
是操作符):malloc/operator new/reserve
得到一塊冰冷的內存,什麼都沒有;new/resize
得到的是一個個鮮活的對象。如果僅需存儲空間的話,malloc/operator new
會更高效。
所以,使用vector
時儘量用reserver
來提高性能。