【48】C++的std::vector使用优化

首先,我们先了解一下vector的工作过程:你创建了一个vector,然后你开始push_back元素,也就是向数组中添加元素;如果vector的容量不够大,不能容纳你想要的新元素,vector需要分配新的内存,至少足够容纳这些想要加入的新元素。当前的vector的内容,从内存中的旧位置复制到内存中的新位置,然后删除掉旧位置的内存。这也就是将代码拖慢的原因之一,也就是我们需要不断地重新分配,这是一个缓慢的操作,我们需要复制所有现有元素,然后重新分配。

这也就是我们目前优化的方向——如何避免复制对象。

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

struct Vertex
{
     float m_x, m_y, m_z;
    
     Vertex(float x, float y, float z)
        : m_x(x), m_y(y), m_z(z)
     {   
     }
     Vertex(const Vertex& vertex)
         :m_x(vertex.m_x), m_y(vertex.m_y), m_z(vertex.m_z)
     {
         std::cout << "Copyed!" << std::endl;
     }
};

std::ostream& operator<<(std::ostream& stream, const Vertex& vertex)
{
    stream << vertex.m_x << "," << vertex.m_y << "," << vertex.m_z;
    return stream;
}

int main()
{
    std::vector<Vertex> vertices(3);
    vertices.push_back({1, 2, 3});
    vertices.push_back({4, 5, 6});![请添加图片描述](https://img-blog.csdnimg.cn/b8092d9295a24234bd398a1acf323988.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmFsYWFhbQ==,size_20,color_FFFFFF,t_70,g_se,x_16)

    vertices.push_back({7, 8, 9});
    return 0;
}

上面代码,最后的运行结果如下:
请添加图片描述
我们可以看到拷贝复制执行了四次。

第29行vertices.push_back({1, 2, 3});可等为vertices.push_back({Vertex(1,2,3)}),我们在栈空间构造了一个vertex对象,然后将其复制到实际的vector创建内存空间中,调用了第一次拷贝构造函数;之后的第30行,因为vector的容量不够,所以vector进行了扩容,将第一次的对象进行了一次拷贝复制,这是第二次调用拷贝构造函数,然后又将第二次创建的对象复制到了实际vector创建的内存空间中,这就是第三次;最后到第31行,将第一个、第二个对象分别进行了一次拷贝,并将第三个对象进行了拷贝至内存空间中。

另一种解释:

vector扩容因子为1.5,初始的capacity为0。第一次push_back,capacity扩容到1,临时对象拷贝到真正的vertices所占内存中,第一次Copied;第二次push_back,发生扩容,capacity扩容到2,vertices发生内存搬移发生的拷贝为第二次Copied,然后再是临时对象的搬移,为第三次Copied;接着第三次push_back,capacity扩容到3(2*1.5 = 3,3之后是4,4之后是6…),vertices发生内存搬移发生的拷贝为第四和第五个Copied,然后再是临时对象的搬移为第六个Copied;

优化步骤一:让编译器知道我们要存储三个对象,即拥有足够的存储容量。

优化步骤二:直接在容器尾部构造元素,省略拷贝过程。

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

struct Vertex
{
     float m_x, m_y, m_z;
    
     Vertex(float x, float y, float z)
        : m_x(x), m_y(y), m_z(z)
     {   
     }
     Vertex(const Vertex& vertex)
         :m_x(vertex.m_x), m_y(vertex.m_y), m_z(vertex.m_z)
     {
         std::cout << "Copyed!" << std::endl;
     }
};

std::ostream& operator<<(std::ostream& stream, const Vertex& vertex)
{
    stream << vertex.m_x << "," << vertex.m_y << "," << vertex.m_z;
    return stream;
}

int main()
{
    std::vector<Vertex> vertices;
    vertices.reserve(3); //分配足够的内存来存储三个vertex对象
    vertices.emplace_back({1, 2, 3}); //传递的不是我们已经构造好了的vertex对象,而是传递了构造函数的参数列表(实际上就是告诉vector,在实际的vector内存中,使用以下参数,构造一个vertex对象。)
    vertices.emplace_back({4, 5, 6});
    vertices.emplace_back({7, 8, 9});
    
    return 0;
}

reserve提前申请内存,避免动态申请开销;
emplace_back直接在容器尾部创建元素,省略拷贝或移动过程。

最后程序运行结果:没有调用拷贝构造函数。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Balaaam

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值