C++ vector容器-45-vector互换和节省空间和预留空间

2023-11-01

这篇来学习vector一个互换操作,也就是有两个vector对象,可以通过一个api,把两个对象互换过来。实际上,就是在内存中交换了对象的指针,原来的指针指向新的vector对象。这种交换有时候是很有必要,特别是匿名vector对象进行交换后可以节约内存空间,最后来看看vector的预留空间相关的知识点。

 

1.两个vector互换

互换的函数很简单swap(vect),当前容器和传进来的vect容器进行交换。下面代码先创建两个vector对象,然后进行打印交换前和交换后的容器元素。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printVector(vector<int> &v)
{
    // for循环迭代器遍历容器内元素
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";   
    }
    cout << endl;

}

void test01()
{
    // vector互换
    vector<int> vec;
    // 1 尾部插入元素
    vec.push_back(2);
    vec.push_back(4);
    vec.push_back(6);
    vec.push_back(8);
    vec.push_back(10);

    vector<int> vec2;
    for(int i=10; i>0; i--)
    {
        vec2.push_back(i);
    }

    cout << "before swap:" << endl;
    printVector(vec);
    printVector(vec2);

    cout << "after swap:" << endl;
    vec.swap(vec2);
    printVector(vec);
    printVector(vec2);
    
}

int main()
{
    test01();
    system("pause");
    return 0;
}

运行结果:

 

举例容器size变小,容量就没有相应变小

有时候一开始我们创建的vector容器的capacity会很大,然后后面代码通过resize函数,使容器元素个数变小,但是容量还是很大,这样就浪费内存空间,看看下面这个例子。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printVector(vector<int> &v)
{
    // for循环迭代器遍历容器内元素
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";   
    }
    cout << endl;

}

void test01()
{
    vector<int> vec;
    for(int i=0; i<100000; i++)
    {
        vec.push_back(i);
    }

    cout << "capacity:" << vec.capacity() << endl;
    cout << "size:" << vec.size() << endl;

    vec.resize(3);
    cout << "capacity:" << vec.capacity() << endl;
    cout << "size:" << vec.size() << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}

结果

在28行代码之后,我们可能只需要存储3个元素,但是这个容器的容量还是初始的时候13万多大小,这个内存空间是无法自动回收,很是浪费内存空间。

 

2.匿名vector对象进行互换后节省内存空间

针对上面这种浪费内存空间的场景,我们可以通过匿名对象调用swap方法来解决。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printVector(vector<int> &v)
{
    // for循环迭代器遍历容器内元素
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";   
    }
    cout << endl;

}

void test01()
{
    vector<int> vec;
    for(int i=0; i<100000; i++)
    {
        vec.push_back(i);
    }

    cout << "capacity:" << vec.capacity() << endl;
    cout << "size:" << vec.size() << endl;

    vec.resize(3);
    vector<int>(vec).swap(vec);
    cout << "capacity:" << vec.capacity() << endl;
    cout << "size:" << vec.size() << endl;
}

int main()
{
    test01();
    system("pause");
    return 0;
}

就增加第29行代码

第29行代码vector<int>(vec),这个部分是一个匿名对象,根据vec的长度,这里就是3去构造一个新的vector<int>对象,这个对象就是一个匿名对象,然后调用swap函数,把vec容器的容量也减少到3. 这个匿名对象只在29行有效,29行结束的时候会自动会编译器回收内存,这个是匿名对象的特点。

 

3.预留空间

下面看看一个vector容器如果要插入10万个数,在g++编译环境下需要动态扩展容器容量多少次才能解决存储10万个数元素

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printVector(vector<int> &v)
{
    // for循环迭代器遍历容器内元素
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";   
    }
    cout << endl;

}

void test01()
{
    vector<int> vec;
    int num = 0; // 统计内存开辟次数
    int *p = NULL;  
    for(int i=0; i<100000; i++)
    {
        vec.push_back(i);
        if(p != &vec[0])
        {
            p = &vec[0];
            num++;
        }
    }

    cout << "num:" << num << endl;
    
}

int main()
{
    test01();
    system("pause");
    return 0;
}

上面这个指针p,一开始是NULL, 我们知道在内存中,数组或者字符串的指针都是默认指向数组第一个元素的位置。这个p就是通过这个特点来统计,只要扩容一次,数组首地址就发生变化一次,这样统计扩容次数的。

我这里是18次出现扩容,如果在vs上可能是30次左右。也就是发生18次动态扩容才搞定这个容器存储10万个数。如果我们一开始就大概知道这个容器需要多少空间,我们可以通过预留空间的办法去减少容器动态扩容的次数。

在vector容器中,预留空间使用reserve(int n)。

reserve(int len);  //容器预留len个元素长度,预留位置不初始化,元素不可以访问

这个预留空间的作用是减少vector在动态扩展容量时的扩展次数,看下面代码

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void printVector(vector<int> &v)
{
    // for循环迭代器遍历容器内元素
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";   
    }
    cout << endl;

}

void test01()
{
    vector<int> vec;
    vec.reserve(100000);
    int num = 0; // 统计内存开辟次数
    int *p = NULL;  
    for(int i=0; i<100000; i++)
    {
        vec.push_back(i);
        if(p != &vec[0])
        {
            p = &vec[0];
            num++;
        }
    }

    cout << "num:" << num << endl;
    
}

int main()
{
    test01();
    system("pause");
    return 0;
}

这样一次就搞定,节约动态扩容的时间。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ vector容器-45-vector互换和节省空间和预留空间 的相关文章

  • 删除文件的最后 10 个字符

    我想删除文件的最后 10 个字符 说一个字符串 hello i am a c learner 是文件内的数据 我只是希望该文件是 hello i am a 文件的最后 10 个字符 即字符串 c learner 应在文件内消除 解决方案 将
  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • C# 异步等待澄清?

    我读了here http blog stephencleary com 2012 02 async and await html that 等待检查等待的看看它是否有already完全的 如果 可等待已经完成 那么该方法将继续 运行 同步
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?

    我有一个 Visual Studio 扩展 它使用 Roslyn 获取当前打开的解决方案中的项目 编译它并从中运行方法 程序员可以修改该项目 我已从当前 VisualStudioWorkspace 成功编译了 Visual Studio 扩
  • 为什么使用小于 32 位的整数?

    我总是喜欢使用最小尺寸的变量 这样效果就很好 但是如果我使用短字节整数而不是整数 并且内存是 32 位字可寻址 这真的会给我带来好处吗 编译器是否会做一些事情来增强内存使用 对于局部变量 它可能没有多大意义 但是在具有数千甚至数百万项的结构
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri

随机推荐

  • Moonbeam开发课程的下一步:Moonbuilder闪亮登场

    本文有所删减 全文链接 Moonbeam开发课程的下一步 Moonbuilder闪亮登场 2021年12月3日 由Moonbeam中文团队与波卡技术社区OneBlock 联合主办的第一期 Moonbeam开发者入门课程 结业典礼以线上直播的
  • 搭建高可用 RocketMQ 集群

    RocketMQ发展历史 RocketMQ是一个由阿里巴巴开源的消息中间件 2012年开源 2017年成为apache顶级项目 RocketMQ在阿里内部应用是非常广泛的 阿里内部的几千个应用都运行在RocketMQ之上 双十一期间需要处理
  • @Resource和@Autowired注解的区别

    介绍 Resource和 Autowired都是做bean的注入时使用 但其实 Resource并不是Spring的注解 它的包是javax annotation Resource 需要导入 但是Spring支持该注解的注入 Spring不
  • 硬件设计31之LVDS与TMDS信号

    1 LVDS基础 原理 图文讲解 LVDS是一种低摆幅的差分信号技术 它使得信号能在差分PCB 线对或平衡电缆上以几百Mbps的速率传输 其低压幅和低电流驱动输出实现了低噪声和低功耗 IEEE 在两个标准中对LVDS 信号进行了定义 ANS
  • 音视频 SDL简介

    一 SDL简介 SDL Simple DirectMedia Layer 是一套开放源代码的跨平台多媒体开发库 使用C语言写成 SDL提供了数种控制图像 声音 输出入的函数 让开发者只要用相同或是相似的代码就可以开发出跨多个平台 Linux
  • 911接线员(C++制作)

    哈喽 鸽了许久的酱某终于回来啦 又来整新活了 在中国 紧急拨号一般分成 110 120 119 但在美国 他们的救援电话是一体的 那就是 911 一款名叫 911接线员 的游戏便应运而生了 但这并不是酱某我的游戏 今天我们就要复刻一下这款策
  • 字符串模式匹配

    字符串模式匹配 1 BF算法 初始时让目标T的第 0 位与模式P的第 0 位对齐 顺序比对目标T与模式P中的对应字符 若 P 与 T 比对发现对应位不匹配 则本趟失配 将 P 右移一位与 T 对齐 进行下一趟比对 若 P 与 T 对应位都相
  • STM8硬件IIC从机

    一 平台 芯片 STM8S103F3P6 环境 IAR STVP 系统 WIN7 二 目的 STM8S103F3P6 使用STM8标准库开发 角色 从机 方式 硬件IIC STM32H7 角色 主机 方式 IO口模拟IIC主机 主机发送命令
  • spark安装部署

    spark安装部署 需要指导私信 所有节点安装scala 安装scala需要安装openjdk 8 jre 当前用户如果没有sudo权限可将其加入sudo组里 以ubuntu2204 LTS为例 sudo apt update sudo a
  • 2023护网日记,护网工作内容、护网事件、告警流量分析

    2023护网日记 一 监控设备 二 工作内容 三 安全事件 1 失陷主机排查 2 后门网站修复 四 告警流量分析 1 信息泄露 2 SQL注入 3 文件上传 4 XSS 跨站脚本 5 代码执行 今年 HW 行动正式开启人员招募 总的来说 人
  • JMETER接口测试,参数关联,断言,定时器,前置处理器,后置处理器,cookie

    jmeter如何测试接口 jmeter可以做性能测试 当然同样可以用来做接口的自动测试 打开jmeter图形界面 右键添加一个线程组 取名 API接口测试 添加一个事务控制器 可以简单的先理解为一个接口组 例如 文件接口 用户接口 登录接口
  • LED+串口通信小试牛刀

    目录 一 搭建STM32的开发环境 1 安装STM32CubeMX 2 安装MDK5 二 闪烁原理 三 STM32CUBEMX生成代码 四 keil仿真调试并生成hex文件 五 运行结果 六 STM32通过串口通信 汇编 1 USART介绍
  • C#关于 SQL Server 数据库的操作

    C 创建SQL Server数据库 设置SQL Server数据库为只读状态 修改和压缩SQL Server数据库 新建 删除和修改 数据表 修改 新增和删除 数据列 代码 using System using System Collect
  • Leetcode——比较版本号

    1 比较版本号 1 字符串模拟 对字符串进行分割 诸位比较 修订号 大小即可 对于缺省的修订号位置 使用 00 进行代指 时间复杂度 令 v1 长度为 n v2 长度为 m 整体复杂度为O max n m 空间复杂度 O n m O n m
  • 敏捷测试

    目录 一 敏捷软件研发思想及在企业中的做法 1 什么是敏捷开发 如何理解 2 敏捷测试常用术语 3 主要角色及职责 4 敏捷开发每日站会 5 Scrum详细解释 6 敏捷软件开发宣言 http agilemanifesto org 7 敏捷
  • 基于PyTorch的深度学习--创建卷积神经网络-面向对象的神经网络

    本篇文章是翻译 https deeplizard com网站中的关于Pytorch学习的文章 供学习使用 原文地址为 https deeplizard com learn video k4jY9L8H89U 使用PyTorch创建神经网络
  • macOS免费串口工具coolTerm/Minicom/Comtool/Volt+(伏特加)/友善串口调试助手/screen/picocom

    macOS下免费的串口调试工具不多 图形化的工具有coolTerm comtool Volt 友善串口调试助手 命令行的工具有minicom screen和picocom 1 coolTerm coolTerm 点击下载mac版 是一个图形
  • win7下面怎么安装Active Directory

    可以先安裝下面補丁 網上可下載 可區分簡體 繁體版 Windows6 1 KB958830 x64 RefreshPkg msu Windows6 1 KB958830 x86 RefreshPkg msu 下面提供方法 1 根據環境選擇所
  • 深度优先遍历(Depth-First Search, DFS)和广度优先遍历(Breadth-First Search, BFS)

    深度优先遍历 DFS 问题1 什么是深度优先遍历 DFS 答案 深度优先遍历是一种用于遍历树或图的算法 它从根节点 或其他起始节点 开始 首先探索尽可能深的分支 然后回溯并继续探索其他分支 它通常使用递归或栈来实现 问题2 如何实现深度优先
  • C++ vector容器-45-vector互换和节省空间和预留空间

    这篇来学习vector一个互换操作 也就是有两个vector对象 可以通过一个api 把两个对象互换过来 实际上 就是在内存中交换了对象的指针 原来的指针指向新的vector对象 这种交换有时候是很有必要 特别是匿名vector对象进行交换