当前位置: 首页 > news >正文

Vector的扩容机制

到需要扩容的时候,Vector会根据需要的大小,创建一个新数组,然后把旧数组的元素复制进新数组。

我们可以看到,扩容后,其实是一个新数组,内部元素的地址已经改变了。所以扩容之后,原先的迭代器会失效:

插一嘴,为什么要用迭代器而不用指针。
Iterator(迭代器)用于提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示
所以原因1:更安全。
第二,迭代器不是指针,它是类模板。它只是通过重载了指针的一些操作符(如“++”、“->”、“ * ”等)来模拟了指针的功能。也因此,它的功能比指针更加智能,他可以根据不同的数据类型实现不同的“++”等操作。
所以原因2:更智能。

int main() {std::vector<int> arr;arr.emplace_back(1);auto it = arr.begin();auto it2 = arr.end();std::cout << *it << "\t" << *(--it2) << std::endl;arr.emplace_back(2);std::cout << *it << "\t" << *(--it2) << std::endl;return 0;
}

执行后,只有第一个cout输出了结果,第二个cout没有输出,直接程序结束。

因为一开始没有声明大小,所以默认cap为0(这里cap指的是vector.capacity(),是可以调用的函数,返回当前vector的实际容量,超过了就要扩容);插入1之后,cap变为1;再插入2,因为size超过了cap,所以要扩容。
如前文所叙,扩容之后,元素的位置都变了,所以原先的迭代器失效了。


问题:元素的位置都变了?那头元素的位置变了吗?

答案是:变了。

有的人在这个时候会有疑问:那我还怎么找到原来的vector?

实际上,vector的头元素地址,与vector的地址并不相同。我们日常将vector叫做数组,但至少在这一点上,它不同于真正的数组。

以下是我做的实验出来的结果:

声明: std::vector<int> vector1 = { 1 };
&vector1: 00EFF824
&vector1[0]: 011B04D0声明: int* p1 = &vector1[0];*p1: 1
指针p1的值(指向的地址): 011B04D0扩容后*p1: -572662307
扩容后,指针p1的值(指向的地址): 011B04D0
扩容后,&vector1: 00EFF824
扩容后,&vector1[0]: 011C0C40声明: int array2[] = { 1 };
&array2: 00EFF7D4
&array2[0]: 00EFF7D4  

从第三部分可以看到,对于一个数组array2,它的地址就是它的头元素的地址。而第一部分中,vector1的地址,与它的头元素地址并不相同。

扩容之后,&vector1 地址还是不变,但是头元素的地址已经变了。

如果你在扩容前,使用一个指针指向头元素,扩容后,指针指向的地址不变,但是这个地方已经变成了野值。


最后,扩容有两种机制,2倍扩容和1.5倍扩容。这个机制随编译器的不同而不同。

VS2017使用的是1.5倍扩容,g++编译器用的是2倍扩容。

在大部分情况下,1.5倍扩容要好一些。因为随着内存的增长,可以实现一定程度上的内存复用。

下面展示两种编译器具体的扩容情况。
以下内容来源于链接。

测试代码:

#include <stdio.h>
#include <vector>
int main() {std::vector<double> v;printf("size:%d capacity:%d max_size:%llu\n",v.size(),v.capacity(),v.max_size());int last_capacity = -1;for (int i = 0; i < v.max_size(); ++i) {v.push_back(1.0*i);if (last_capacity!=v.capacity()) {printf("size:%10d capacity:%10d c/l:%d max_size:%llu\n",v.size(),v.capacity(),v.capacity()/last_capacity,v.max_size());}last_capacity = v.capacity();}return 0;
}

上面是vs2017的1.5倍扩容,下面是g++的2倍扩容:
在这里插入图片描述
在这里插入图片描述
vector的capacity,是指当前状态下(未重新向操作系统申请内存前)的最大容量。

这个值如果不指定,则开始是0,加入第一个值时,由于capacity不够,向操作系统申请了长度为1的内存。在这之后每次capacity不足时,都会重新向操作系统申请长度为原来两倍的内存。


回到刚才的话题:为什么1.5倍扩容要好一些?

以下内容来源于链接。

  • 两倍扩容

假设我们一开始申请了 16Byte 的空间。
当需要更多空间的时候,将首先申请 32Byte,然后释放掉之前的 16Byte。这释放掉的16Byte 的空间就闲置在了内存中。
当还需要更多空间的时候,你将首先申请 64Byte,然后释放掉之前的 32Byte。这将在内存中留下一个48Byte 的闲置空间(假定之前的 16Byte 和此时释放的32Byte 合并)
当还需要更多空间的时候,你将首先申请128Byte,然后释放掉之前的 64 Byte。这将在内存中留下一个112Byte 的闲置空间(假定所有之前释放的空间都合并成了一个块)

扩容因子为2时,上述例子表明:每次扩容,我们释放掉的内存连接起来的大小,都小于即将要分配的内存大小。

  • 1.5倍扩容

假设我们一开始申请了 16Byte 的空间。
当需要更多空间的时候,将申请 24 Byte ,然后释放掉 16 ,在内存中留下 16Byte 的空闲空间。
当需要更多空间的时候,将申请 36 Byte,然后释放掉 24,在内存中留下 40Byte (16 + 24)的空闲空间。
当需要更多空间的时候,将申请 54 Byte,然后释放 36,在内存中留下 76Byte。
当需要更多空间的时候,将申请 81 Byte,然后释放 54, 在内存中留下 130Byte。
当需要更多空间的时候,将申请 122 Byte 的空间(复用内存中闲置的 130Byte)

由此可见,1.5倍扩容在一定程度上可以实现内存的复用。当然,每次扩容的大小更小,也意味着时间效率的降低,看取舍了。

相关文章:

Vector的扩容机制

到需要扩容的时候&#xff0c;Vector会根据需要的大小&#xff0c;创建一个新数组&#xff0c;然后把旧数组的元素复制进新数组。 我们可以看到&#xff0c;扩容后&#xff0c;其实是一个新数组&#xff0c;内部元素的地址已经改变了。所以扩容之后&#xff0c;原先的迭代器会…...

22讲MySQL有哪些“饮鸩止渴”提高性能的方法

短连接风暴 是指数据库有很多链接之后只执行了几个语句就断开的客户端&#xff0c;然后我们知道数据库客户端和数据库每次连接不仅需要tcp的三次握手&#xff0c;而且还有mysql的鉴权操作都要占用很多服务器的资源。话虽如此但是如果连接的不多的话其实这点资源无所谓的。 但是…...

10.0自定义SystemUI下拉状态栏和通知栏视图(六)之监听系统通知

1.前言 在进行rom产品定制化开发中,在10.0中针对systemui下拉状态栏和通知栏的定制UI的工作开发中,原生系统的下拉状态栏和通知栏的视图UI在产品开发中会不太满足功能, 所以根据产品需要来自定义SystemUI的下拉状态栏和通知栏功能,首选实现的就是下拉通知栏左滑删除通知的部…...

怎样在外网登录访问CRM管理系统?

一、什么是CRM管理系统&#xff1f; Customer Relationship Management&#xff0c;简称CRM&#xff0c;指客户关系管理&#xff0c;是企业利用信息互联网技术&#xff0c;协调企业、顾客和服务上的交互&#xff0c;提升管理服务。为了企业信息安全以及使用方便&#xff0c;企…...

Activity工作流(三):Service服务

3. Service服务 所有的Service都通过流程引擎获得。 3.1 RepositoryService 仓库服务是存储相关的服务&#xff0c;一般用来部署流程文件&#xff0c;获取流程文件&#xff08;bpmn和图片&#xff09;&#xff0c;查询流程定义信息等操作&#xff0c;是引擎中的一个重要的服务。…...

算法--最长回文子串--java--python

这个算法题里面总是有 暴力解法 把所有字串都拿出来判断一下 这里有小小的优化&#xff1a; 就是当判断的字串小于等于我们自己求得的最长回文子串的长度&#xff0c;那么我们就不需要在进行对这个的判断这里的begin&#xff0c;还可以用来取得最小回文子串是什么 java // 暴…...

ElasticSearch-第二天

目录 文档批量操作 批量获取文档数据 批量操作文档数据 DSL语言高级查询 DSL概述 无查询条件 叶子条件查询 模糊匹配 match的复杂用法 精确匹配 组合条件查询(多条件查询) 连接查询(多文档合并查询) 查询DSL和过滤DSL 区别 query DSL filter DSL Query方式查…...

【AI大比拼】文心一言 VS ChatGPT-4

摘要&#xff1a;本文将对比分析两款知名的 AI 对话引擎&#xff1a;文心一言和 OpenAI 的 ChatGPT&#xff0c;通过实际案例让大家对这两款对话引擎有更深入的了解&#xff0c;以便大家选择合适的 AI 对话引擎。 亲爱的 CSDN 朋友们&#xff0c;大家好&#xff01;近年来&…...

美团笔试-3.18

1、捕获敌人 小美在玩一项游戏。该游戏的目标是尽可能抓获敌人。 敌人的位置将被一个二维坐标 (x, y) 所描述。 小美有一个全屏技能&#xff0c;该技能能一次性将若干敌人一次性捕获。 捕获的敌人之间的横坐标的最大差值不能大于A&#xff0c;纵坐标的最大差值不能大于B。 现在…...

【12】SCI易中期刊推荐——计算机信息系统(中科院4区)

🚀🚀🚀NEW!!!SCI易中期刊推荐栏目来啦 ~ 📚🍀 SCI即《科学引文索引》(Science Citation Index, SCI),是1961年由美国科学信息研究所(Institute for Scientific Information, ISI)创办的文献检索工具,创始人是美国著名情报专家尤金加菲尔德(Eugene Garfield…...

好不容易约来了一位程序员来面试,结果人家不做笔试题

感觉以后还是不要出面试题这环节好了。好不容易约来了一位程序员来面试。刚递给他一份笔试题&#xff0c;他一看到要做笔试题&#xff0c;说不做笔试题&#xff0c;有问题面谈就好了&#xff0c;搞得我有点尴尬&#xff0c;这位应聘者有3年多工作经验。关于程序员岗位&#xff…...

这几个过时Java技术不要再学了

Java 已经发展了近20年&#xff0c;极其丰富的周边框架打造了一个繁荣稳固的生态圈。 Java现在不仅仅是一门语言&#xff0c;而且还是一整个生态体系&#xff0c;实在是太庞大了&#xff0c;从诞生到现在&#xff0c;有无数的技术在不断的推出&#xff0c;也有很多技术在不断的…...

EEPROM芯片(24c02)使用详解(I2C通信时序分析、操作源码分析、原理图分析)

1、前言 (1)本文主要是通过24c02芯片来讲解I2C接口的EEPROM操作方法&#xff0c;包含底层时序和读写的代码&#xff1b; (2)大部分代码是EEPROM芯片通用的&#xff0c;但是其中关于某些时间的要求&#xff0c;是和具体芯片相关的&#xff0c;和主控芯片和外设芯片都有关系&…...

Django4.0新特性-主要变化

Django 4.0于2021年12月正式发布&#xff0c;标志着Django 4.X时代的来临。参考Django 4.0 release notes | Django documentation | Django Python 兼容性 Django 4.0 将支持 Python 3.8、3.9 与 3.10。强烈推荐并且仅官方支持每个系列的最新版本。 Django 3.2.x 系列是最后…...

MySQL高级面试题整理

1. 执行流程 mysql客户端先与服务器建立连接Sql语句通过解析器形成解析树再通过预处理器形成新解析树&#xff0c;检查解析树是否合法通过查询优化器将其转换成执行计划&#xff0c;优化器找到最适合的执行计划执行器执行sql 2. MYISAM和InNoDB的区别 MYISAM&#xff1a;不支…...

【Java】面向对象三大基本特征

【Java】面向对象三大基本特征 1.封装 On Java 8:研发程序员开发一个工具类&#xff0c;该工具类仅向应用程序员公开必要的内容&#xff0c;并隐藏内部实现的细节。这样可以有效地避免该工具类被错误的使用和更改&#xff0c;从而减少程序出错的可能。彼此职责划分清晰&#x…...

蓝桥杯C++组怒刷50道真题(填空题)

&#x1f33c;深夜伤感网抑云 - 南辰Music/御小兮 - 单曲 - 网易云音乐 &#x1f33c;多年后再见你 - 乔洋/周林枫 - 单曲 - 网易云音乐 18~22年真题&#xff0c;50题才停更&#xff0c;课业繁忙&#xff0c;有空就更&#xff0c;2023/3/18/23:01写下 目录 &#x1f44a;填…...

Shell自动化管理 for ORACLE DBA

1.自动收集每天早上9点到晚上8点之间的AWR报告。 auto_awr.sh #!/bin/bash# Set variables ORACLE_HOME/u01/app/oracle/product/12.1.0/dbhome_1 ORACLE_SIDorcl AWR_DIR/home/oracle/AWR# Set date format for file naming DATE$(date %Y%m%d%H%M%S)# Check current time - …...

Unity学习日记13(画布相关)

目录 创建画布 对画布的目标图片进行射线检测 拉锚点 UI文本框使用 按钮 按钮导航 按钮触发事件 输入框 实现单选框 下拉菜单 多选框选项加图片 创建画布 渲染模式 第一个&#xff0c;保持画布在最前方&#xff0c;画布内的内容显示优先级最高。 第二个&#xff0c;…...

初阶C语言:冒泡排序

冒泡排序是一种简单的排序算法&#xff0c;它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换&#xff0c;也就是说该数列已经排序完成。1.冒泡排序关于冒泡排序我们在讲…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...