共计 2031 个字符,预计需要花费 6 分钟才能阅读完成。
转载请注明文章出处: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
来提高性能。
参考
- std::vector::resize
- Does the vector.resize() method calls the default elements constructors when resizing?