48Vector的优化使用 in C++
vector能来回变化容量的原理是:新增一个元素,而数组容量不能容纳新元素,那么它就会开辟新的更大的内存块,把原有的和新增的元素全复制过去,然后把旧的内存块删除
这种调整大小,重新分配的操作是很费时的(复制所以元素+重新分配),而这是要避免的,而这便是优化的方向,对于复制的优化策略。
我们如何避免复制对象呢?特别是基于vector的对象(没有储存vecotr指针,而是对象)
🍅寻找策略
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
class Entity {
public:
int x, y, z;
Entity() {}
Entity(const Entity &other) {
cout << "复制" << endl;
}
};
int main()
{
std::vector<Entity>vec;//1次
vec.push_back(Entity());
//程序结果是:输出了 一 个 “复制”
return 0;
}
出现这个的原因是:当我们在创建Entity
时,我们在main
的栈上创建了它,然后从main
函数复制到了实际的vector
中
- 这就引出第一个策略:如果能直接把Entity建立在vector分配的内存中,就可以省略复制这一步操作
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
class Entity {
public:
int x, y, z;
Entity() {}
Entity(const Entity &other) {
cout << "复制" << endl;
}
};
int main()
{
std::vector<Entity>vec;
vec.push_back(Entity());//1次
vec.push_back(Entity());//2次
//程序结果是:输出了 三 个 “复制”
return 0;
}
三个复制,有两个复制是因为上面的原因:两次从主函数复制到vector中,而还有一次复制是因为第一次的vector容量是1,装不下两个元素,所以它需要扩容成容量2,然后把原数组的第一个元素复制过去,然后再把新的第二个元素装进去,这就是第三个复制。
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
class Entity {
public:
int x, y, z;
Entity() {}
Entity(const Entity &other) {
cout << "复制" << endl;
}
};
int main()
{
std::vector<Entity>vec;
vec.push_back(Entity());//1
vec.push_back(Entity());//2
vec.push_back(Entity());//3
//会输出 六 个 “复制”
return 0;
}
同理,要从主函数复制到vector三次,然后两次扩容,第一次扩容时把原vector里的一个元素复制新vector里,第二次扩容时把原vector里的两个元素复制新vector里,所以又有三次复制
- 所以这类有第二个优化策略:可以直接告诉vector指定容量就是3,这样子就不需要扩容了
🍅优化手段
💡💡💡设置vector容量:[vector名字].reserve([容量])
,解决反复扩容问题
-
std::vector<Entity> vec; vec.reserve(3); //把vector的容量设置为3
这个与下面这个是有区别的
std::vector<Entity> vec(3); //这个是直接在定义vector的时候就设置3
这里设置的结果不是把容量扩容成3,它实际上会构造三个Entity对象,即是一开始就是满的,不是空的!!!!
但最初的想法只是有足够的内存来容纳它们,而不是一上来就创建三个对象把它们填满
而
reserve
函数的功能就是单纯创建足够的内存,其余多余的什么也不干(如果不用reserve的话,复制的操作数会以指数级别增长!)
💡💡💡用emplace_back
代替push_back
,解决反复复制问题
如果用push_back
,那么进行的操作是从主函数复制对象到vector中
而如果用emplace_back
,则是直接在实际的vector中构造
vec.push_back(Entity(1, 2, 3));
//push_back需要传递我们已经构建的Entity对象
vec.emplace_back(1, 2, 3);
//emplace_back则不需要传递已构建的Entity对象,只需要传递了构造函数的参数列表
//相当于告诉vector:在我们实际的vector内存中,使用以下参数(参数列表),构造一个Entity对象(直接在vector里)
如果完成了上面两种优化策略,则不会出现一个复制操作,而这只是简单的优化策略,但是可以比最初的代码快一个阶级
这里的内容实在是太有用了!!!!!!!!