std::vector的用法优化

std::vector的用法优化

背景

最近看std的库和相关的API文档,然后就直接调用了。感觉自己好像学会了新工具,实际发现写出来的性能和老手相差很大。首先,建议大家看一下操作系统的书,了解什么是堆栈,内存的复制,回收释放等原理,在此基础上,了解std库就会有更深的见解。下面的例子是在Youtube学习编程优化的总结,分享给需要的同行。

用法优化示例

话不多说,先贴代码:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct Vertex{
    float x, y, z;
    Vertex(float x, float y, float z):x(x), y(y),z(z){}
    Vertex(const Vertex& vertex):x(vertex.x), y(vertex.y), z(vertex.z){
        std::cout<<"copied"<<std::endl;
    }
};
int main()
{
    std::vector<Vertex> vertics;
    //vertics.reserve(3);
    vertics.push_back({1, 2, 3});
    vertics.push_back({4, 5, 6});
    vertics.push_back({7, 8, 9});
    return 0;
}

这是一个大家都熟悉的写法,参考API文档很容易写成如上的代码。上述代码的执行结果如下:

copied
copied
copied
copied
copied
copied

内存复制了6次,为什么呢?

  1. 第一次copy,{1,2,3}初始化Vertex,然后copy到vector内,此时vertics的capacity为1。
  2. 第二次copy,vertics空间不够,进行重新开辟空间,将{1,2,3}copy到新的vectics内。
  3. 第三次copy,{4,5,6}初始化Vertex,然后copy到vector内,此时vertics的capacity为2。
  4. 第四,五次copy,vertics空间又不够,再次重新开辟空间,将{1,2,3},{4,5,6}copy到新的vertics内。
  5. 第六次copy,{7,8,9初始化Vertex,然后copy到vector内,此时vertics的capacity为3。

短短的几行代码就存在如此多的内存复制,按照很多人的习惯,肯定就是循环里写push_back,那么copy的次数将会以O ( n 2 ) O(n^2)O(n2)平方增长。是不是顿时找到自己代码慢的原因了?

如何优化这个代码呢?第一步,预先评估一下vector的空间,使用reserve预留vector的空间。这里强调一下,这里是reserve不是resize,两者区别是:reserve是容器预留空间,不创建元素对象,在创建对象之间,不能引用容器内元素,因此加入新元素的时候,需要用push_back()/insert()等函数;resize()是改变容器大小,并且创建对象。调用函数以后,就可以直接引用容器内对象了,可以使用[]的形式访问对象,或者迭代器访问。如果这里误写成,resize(3) 如下所示:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct Vertex{
    float x, y, z;
    Vertex(float x =0, float y =0, float z=0):x(x), y(y),z(z){}
    Vertex(const Vertex& vertex):x(vertex.x), y(vertex.y), z(vertex.z){
        std::cout<<"copied"<<std::endl;
    }
};
int main()
{
    std::vector<Vertex> vertics;
    //vertics.resize(3);     // copy 6次 
    //vertics.resize(3, {0, 0, 0}); // copy 9次
    //vertics.reserve(3); // copy 3次
    vertics.push_back({1, 2, 3});
    vertics.push_back({4, 5, 6});
    vertics.push_back({7, 8, 9});
    return 0;
}

vertics.push_back这里其实也存在内存copy,可以使用emplace_back()函数,这样最终版的代码如下:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct Vertex{
    float x, y, z;
    Vertex(float x =0, float y =0, float z=0):x(x), y(y),z(z){}
    Vertex(const Vertex& vertex):x(vertex.x), y(vertex.y), z(vertex.z){
        std::cout<<"copied"<<std::endl;
    }
};
int main()
{
    std::vector<Vertex> vertics;
    //vertics.resize(3);//, {0,0,0});
    vertics.reserve(3);
    /*
    vertics.push_back({1, 2, 3});
    vertics.push_back({4, 5, 6});
    vertics.push_back({7, 8, 9});*/
    vertics.emplace_back(1,2,3);
    vertics.emplace_back(4,5,6);
    vertics.emplace_back(7, 8, 9);
    return 0;
}

不存在内存copy,有兴趣的同学可以使用一些循环,来测试不同方法的执行速度。


版权声明:本文为zijin0802034原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。