提高STL vector性能的6个技巧

本文介绍了提高STL vector性能的六个技巧,包括:1) 提前预留向量大小避免重新分配;2) 使用shrink_to_fit()释放内存;3) 优先选择赋值而非insert()或push_back();4) 避免在迭代时使用at()函数;5) 避免在vector头部插入数据;6) 使用emplace_back()代替push_back()。通过这些技巧,可以显著提升vector的运行效率。


简介

用Bjarne Stroustrup的话来说:默认情况下,当你需要一个容器时使用 Vector。

Vector 只是一个工具,像任何工具一样,它可以有效地使用,也可以无效地使用。

本文介绍 6 种优化vector使用的方法,研究使用vector执行最常见编程任务的有效和低效方法,衡量我们通过有效使用vector获得的性能增益,并尝试理解为什么我们会获得性能增益。

性能测试的实施方法

用标准库 chrono 制作一个秒表记录函数运行时间,我们将每个测试运行100次取平均运行时间进行比较。

代码放最后链接里。

注意:结果测试用 Release,别用Debug。

运行结果:
在这里插入图片描述

一 、通过提前保留向量的大小来避免不必要的重新分配和复制周期

程序员喜欢vector是因为可以向容器中添加项目时无需提前担心容器的大小。但是,仅从容量为 0 的vector开始并在元素进来时添加它可能会花费相当多的运行时性能,如果你提前知道你的 vector 可以有多大,那么提前保留大小是值得的。

  // #1: 通过提前保留vector的大小,避免不必要的重新分配和复制周期。
    vector<BigTestStruct> testVector1;
    vector<BigTestStruct> testVector2;
    for (int i = 0; i < 100; i++)
    {
        sw.Restart(); //重置时间
        FillVector(testVector1); //添加一个数据结构体
        tg.test1 += sw.ElapsedUs(); //微妙

        sw.Restart();
        //重点:用reserve先储备10000个空间
        testVector2.reserve(10000);
        FillVector(testVector2);
        tg.test2 += sw.ElapsedUs();

        testVector1.clear(); //清除内容
        testVector1.shrink_to_fit(); //通过释放未使用的内存来减少内存使用
        testVector2.clear();
        testVector2.shrink_to_fit();
    }
    cout << "\n无预约填充vector的平均时间:" << (tg.test1 / 100) << endl;
    cout << "有无预约填充vector的平均时间:" << (tg.test2 / 100) << endl;

在我电脑上跑,未提前保留大小用时 7027.3 微妙 , 前保留只需要 1950.07 微妙,性能提高71%

在这里插入图片描述

这背后的原因 Scott Meyers 在他的书 " Effective STL:50条有效使用STL的经验 " 中有解释。

对于vector 和string,每当需要更多空间时,就会执行类似于realloc的操作。这种类似realloc的操作有四个部分:

  1. 分配一个新的内存块,它是容器当前容量的若干倍。在大多数实现中,vector 和string 容量每次增长 1.5 到 2 倍
  2. 将容器旧内存中的所有元素复制到新内存中
  3. 销毁旧内存中的对象
  4. 释放旧内存

分配、回收、复制和销毁一套下来就是70%的性能。

二、使用shrink_to_fit()来释放vector ,别用clear()或erase()清除内容而不释放内存。

shrink_to_fit:通过释放未使用的内存来减少内存使用。

clear:清除内容

erase:擦除元素

通过 erase() 或 clear() 方法从向量中删除元素不会释放vector分配的内存。

在这里插入图片描述

不要的内存一定要用shrink_to_fit释放掉。

shrink_to_fit可能不是所有编译器都支持,可以使用swap。

container<T>( c ).swap( c )

container<T>().swap( c )

将容器中的内容与其他内容交换。不对单个元素调用任何移动、复制或交换操作。

三、当填充或复制到vector中时,最好选择 ‘=’ 赋值而不是insert()或push_back()

在这里插入图片描述

赋值非常有效,因为它知道它正在复制的向量的大小,并且只需要调用一次内存管理器来创建分配向量的内部缓冲区。

四、在迭代 vector 中的元素时,避免使用at() 函数

三种遍历vector的方法:

  1. 使用 iterator
  2. 使用 at()
  3. 使用下标 [ ]
    在这里插入图片描述

结果:at() 函数是三种访问向量元素的方法中最慢的

五、vector别在头部插入数据

在这里插入图片描述

相差太多,vector的头部插入是一个 O(1) 操作。向量越大,性能越差。

6、vector插入数据时emplace_back比push_back效率高

在这里插入图片描述

代码

https://blog.csdn.net/a15322910600/article/details/121282425

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值