C++ | 高效使用vector

news2024/11/27 21:36:33

C++ | 高效使用vector

文章目录

  • C++ | 高效使用vector
    • 1.善用Reserve
    • 2.移动构造和赋值
    • 3.释放vector
    • 如果vector内存的是指针,需要先释放每个指针所指内存,再释放vector
    • Reference

1.善用Reserve

当需要向vector中添加元素但目前的空间已经放满时,vector会再分配一块更大的空间,先将已有元素拷贝或移动过去,再添加新的元素。

如果频繁向vector中存入元素,就会造成频繁的内存分配和元素移动。

因此如果预知存入vector成员的个数,可以使用reserve分配好内存空间,避免空间不够的时候再次分配空间。

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

using namespace std::chrono;
 
void randy_reserve() {
    for(int i = 0; i < 1024 * 1024; i++) {
       std::vector<int> randy;
        randy.reserve(10000);
        for(int j = 0; j < 10000; j++) {
            randy.push_back(j);
        }
    }
}

void randy_without_reserve() {
    for(int i = 0; i < 1024 * 1024; i++) {
        std::vector<int> randy;
        for(int j = 0; j < 10000; j++) {
            randy.push_back(j);
        }
    }
}

template<typename F>
void timeit(std::string sanjiejiyuan, F &&f) {
    auto st = steady_clock::now();
    f();
    auto ed = steady_clock::now();
    auto diff = duration_cast<duration<double>>(ed - st);
    std::cout << sanjiejiyuan << diff.count() << " seconds" << std::endl;
}

int main() {
    timeit("use reserve: ", randy_reserve);
    timeit("no use reserve: ", randy_without_reserve);
    return 0;
}

结果:

vector 大小为100时耗时
use reserve: 1.04476 seconds
no use reserve: 1.8501 seconds

vector 大小为10000时耗时
use reserve: 95.5728 seconds
no use reserve: 93.7059 seconds

可以看出来,当vector较小时,频繁使用效果比较明显。所以当能够明确知道需要存储多少数据量到vector中去的时候,就提前预留多少内存空间,可以避免vector因为空间不够而不断开辟空间,造成时间消耗。

2.移动构造和赋值

如果将拷贝自定义类型到vector的方式改成移动构造和赋值,能够顾减少不必要的性能开销。

vector移动元素的场景:

  • 扩展内存空间,拷贝元素到新的内存空间
  • 插入非尾部位置的元素时,移动该元素后面元素到尾部元素向后1格
  • 删除元素(非尾部)时,移动该元素后面元素到尾部元素向前1格
  • 不同vector相互赋值等
class Copy {
 public:
  Copy() noexcept : randy(1024, 'q') {}
  Copy(const Copy &sesame) noexcept : randy(sesame.randy) {}
  Copy(Copy &&) = delete;
  ~Copy() {}

 private:
  std::string randy;
};

class FakeMove {
 public:
  FakeMove() noexcept : randy(1024, 'q') {}
  FakeMove(FakeMove &&sesame) : randy(std::move(sesame.randy)) {}
  FakeMove(const FakeMove &sesame) noexcept : randy(sesame.randy) {}
  ~FakeMove() {}

 private:
  std::string randy;
};
class Move {
 public:
  Move() noexcept : randy(1024, 'q') {}
  Move(Move &&sesame) noexcept : randy(std::move(sesame.randy)) {}
  Move(const Move &sesame) noexcept : randy(std::move(sesame.randy)) {}
  ~Move() {}

 private:
  std::string randy;
};

void QCopy() {
    
    for(int i = 0; i < 4096; i++) {
        std::vector<Copy> target;
        for(int j = 0; j < 150; j++) {
            Copy c;
            target.push_back(c);
        }
    }
}
template<typename T>
void QMove() {
    for(int i = 0; i < 4096; i++) {
        std::vector<T> target;
        for(int j = 0; j < 150; j++) {
            T h;
            target.emplace_back(h);
        }
    }
}
 
int main() {
    timeit("Copy: ", QCopy);
    timeit("FakeMove: ", QMove<FakeMove>);
    timeit("Move: ", QMove<Move>);
    return 0;
}

结果:

Copy: 0.24857 seconds
FakeMove: 0.150558 seconds
Move: 0.108038 seconds

Move 类声明移动构造时的noexcept保证不抛出异常。noexcept 编译期完成声明和检查工作,表示函数不会抛出异常。

3.释放vector

在某个时间点后再也不会用到vector了,可以释放它所占用的空间及其成员所占用的空间。

int main() {
     std::vector<int> randy;
    for (int i = 0; i < 20; i++) {
        randy.push_back(i);
    }
    
    std::cout << "randy size: " << randy.size() << " capacity: " << randy.capacity()
              << std::endl;

    randy.clear();
    std::cout << "after clear, randy size: " << randy.size() << " capacity: " << randy.capacity()
              << std::endl;

    std::vector<int>().swap(randy);
    std::cout << "swap with empty vector, randy size: " << randy.size() << " capacity: " << randy.capacity()
              << std::endl;

    return 0;
}

运行结果:

randy size: 20 capacity: 32
after clear, randy size: 0 capacity: 32
swap with empty vector, randy size: 0 capacity: 0

真正释放内存是在vector的析构函数里进行的,所以一旦超出vector的作用域,首先它所保存的所有对象会被析构,然后会调用allocator中的deallocate函数回收对象本身的内存。

上述释放内存代码 std::vector<int>().swap(randy);可以替换为以下形式:

{
     std::vector<int> randy;
    for (int i = 0; i < 20; i++) {
        randy.push_back(i);
    }
} // 离开作用域,randy会调用自己的析构函数释放内存

如果vector内存的是指针,需要先释放每个指针所指内存,再释放vector

    std::vector<Randy *> sanjie(20, new Randy());

    for (size_t i = 0; i < 20; i++) {
      delete sanjie[i];
      sanjie[i] = nullptr;
    }
    randy.clear();
    std::vector<Randy *>().swap(sanjie);

Reference

  • std::vector的小技巧
  • vector 动态删除元素,释放内存的研究

欢迎关注公众号【三戒纪元】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/528872.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

200G AOC有源光缆在数据中心的应用

随着大数据时代对高速、高带宽的需求日益增长&#xff0c;人们迫切需要一种新型产品作为高性能计算和数据中心的主要传输介质。因此&#xff0c;光通信传输速率的发展也提高了。面对短距离数据中心在光互连产品中的高速、高密度、低成本、低功耗要求&#xff0c;AOC有源光缆提供…

shell脚本----awk命令

文章目录 一、awk工作原理二、awk相关命令三、awk的使用按行输出文本:按字段输出文本&#xff1a;通过管道、双引号调用 Shell 命令&#xff1a; 一、awk工作原理 逐行读取文本&#xff0c;默认以空格或tab键为分隔符进行分隔&#xff0c;将分隔所得的各个字段保存到内建变量中…

Flink Kafka-Source

文章目录 Kafka Source1. 使用方法2. Topic / Partition 订阅3. 消息解析4. 起始消费位点5. 有界 / 无界模式6. 其他属性7. 动态分区检查8. 事件时间和水印9. 空闲10. 消费位点提交11. 监控12. 安全 Apache Kafka 连接器 Flink 提供了 Apache Kafka 连接器使用精确一次&#xf…

由浅入深理解java集合(四)——集合 Queue

Queue用于模拟队列这种数据结构&#xff0c;队列通常是指“先进先出”&#xff08;FIFO&#xff09;的容器。新元素插入&#xff08;offer&#xff09;到队列的尾部&#xff0c;访问元素&#xff08;poll&#xff09;操作会返回队列头部的元素。通常&#xff0c;队列不允许随机…

【C++初阶】类与对象(中)之构造函数与析构函数

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

C++继承详解——基类派生类对象赋值转换、菱形虚拟继承

hello&#xff0c;这里是bangbang&#xff0c;今天来讲下继承。 面向对象三大特性&#xff1a;封装、继承、多态。 目录 1. 继承的概念及定义 1.1 继承的概念 1.2 继承定义 1.2.1 定义格式 1.2.2 继承关系和访问限定符 1.2.3 继承基类成员访问方式的变化 2. 基类和派生类对…

Java面试知识点(全)-设计模式二

Java面试知识点(全) 导航&#xff1a; https://nanxiang.blog.csdn.net/article/details/130640392 注&#xff1a;随时更新 13.模板模式 定义一个操作中算法的骨架&#xff0c;而将一些步骤延迟到子类中&#xff0c;模板方法使得子类可以不改变算法的结构即可重定义该算法的…

7. 深入理解MVCC与BufferPool缓存机制

MySQL性能调优 1. MVCC多版本并发控制机制1.1 undo日志版本链与read view机制详解 2. Innodb引擎SQL执行的BufferPool缓存机制 本文是按照自己的理解进行笔记总结&#xff0c;如有不正确的地方&#xff0c;还望大佬多多指点纠正&#xff0c;勿喷。 本节课内容&#xff1a; 1、…

PowerShell install 一键部署VMware_Workstation

VMware Workstation 前言 VMware Workstation Pro 是业界标准的桌面 Hypervisor&#xff0c;用于在 Linux 或 Windows PC 上运行虚拟机 download VMware_Workstation VMware_Workstation WindowsVMware_Workstation linux文档downloaddownload参考 前提条件 开启wmi,配置…

2023接口自动化测试框架9项必备功能(建议收藏)

当你准备使用一个接口测试框架或者自造轮子的时候&#xff0c;或许你需要先了解下一个接口自动化测试框架必须具备什么功能。 一、校验 这个很好了解&#xff0c;如果没有校验&#xff0c;单纯的执行接口的话&#xff0c;那就谈不上测试了。所以支持对返回值校验是一个必须的…

【集合详解】——python基础——如桃花来

目录索引 集合的特点&#xff1a;创建集合&#xff1a;集合常见操作&#xff1a;增加数据&#xff1a;*add():**update():* 删除数据&#xff1a;*remove():**discard():**pop():* 查找数据&#xff1a;*in:**not in:* 集合的特点&#xff1a; 没有重复元素,即使重复&#xff0…

【ONE·C++ || set和map(三):基于红黑树的封装框架】

总言 主要介绍map、set的封装框架。 文章目录 总言1、基本框架说明2、map、set封装Ⅰ&#xff1a;用于比较的仿函数3、map、set封装Ⅱ&#xff1a;迭代器实现3.1、基本说明3.2、begin()、end()、operator*、operator&、operator、operator!3.2.1、begin()、end()3.2.2、op…

( 位运算 ) 693. 交替位二进制数 / 476. 数字的补数 ——【Leetcode每日一题】

❓ 题目一 693. 交替位二进制数 难度&#xff1a;简单 给定一个正整数&#xff0c;检查它的二进制表示是否总是 0、1 交替出现&#xff1a;换句话说&#xff0c;就是二进制表示中相邻两位的数字永不相同。 示例 1&#xff1a; 输入&#xff1a;n 5 输出&#xff1a;true 解…

使用inbuilder完成UBML低代码设计

文章目录 一、活动介绍二、我所认识的低代码平台三、使用inbuilder开发工具拖拉跩实现 低代码产品开发四、环境搭建五、5分钟完成低代码实验六、财务报销报表实验活动成果截图七、总结 一、活动介绍 开放原子训练营开启inBuilder低代码实验室活动。无论您是计算机行业相关从业…

(css)el-select多选以tag展示时,超过显示长度以...省略号显示

(css)el-select多选以tag展示时&#xff0c;超过显示长度以…省略号显示 效果 代码&#xff1a; <span>系统词典维度&#xff1a;</span><el-selectv-model"dNum"placeholder"请选择"multiplecollapse-tags //设置collapse-tags属性将它…

Windows批处理指令

前言 批处理文件&#xff08;batch file&#xff09;包含一系列 DOS 命令&#xff0c;通常用于自动执行重复性任务。用户只需双击批处理文件便可执行任务&#xff0c;而无需重复输入相同指令。编写批处理文件非常简单&#xff0c;但难点在于确保一切按顺序执行。编写严谨的批处…

Java进阶-面向对象入门

1. 面向过程与面向对象 1.1 何谓“面向对象”的编程思想&#xff1f; 首先解释一下“思想”。 先问你个问题&#xff1a;你想做个怎样的人&#xff1f; 可能你会回答&#xff1a;我想做个好人&#xff0c;孝敬父母&#xff0c;尊重长辈&#xff0c;关爱亲朋…… 你看&#…

2023年Android开发者路线-第2部分

2023年Android开发者路线-第1部分 2023年Android开发者路线-第2部分 2023年Android开发者路线-第3部分 2023年Android开发者路线-第4部分 2023Android开发者路线-第2部分 在上一篇文章中&#xff0c;我们讨论了 Android 架构的重要元素&#xff0c;包括主要的 Android 语言…

探索iOS之AVFoundation框架

AVFoundation框架的业务层主要是AVKit和UIKit&#xff0c;内核层包括CoreVideo、CoreAudio、CoreMedia、VideoToolBox等。AVFoundation作为iOS的音视频框架&#xff0c;提供音视频播放、录制、编辑、编解码、音效设置等。接下来&#xff0c;让我们看一下整体的框架图。 一、AVK…

ANR基础篇 - Trace.txt文件分析

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录前言一、trace.txt文件示例二、日志分析2.1 CPU 负载2.2 内存信息2.3 堆栈信息schedst…