news 2026/4/20 23:09:16

C++零基础到工程实战(4.3.5):vector元素空间和内存空间显示与控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++零基础到工程实战(4.3.5):vector元素空间和内存空间显示与控制

目录

一、前言

二、本节代码示例

三、什么是vector的元素空间和内存空间

3.1 元素空间:已经真正存在的元素个数

3.2 内存空间:已经分配好的容量大小

3.3 一定要区分:size不是capacity

(1)size()

(2)capacity()

3.4 capacity显示的不是字节数

四、vector空间控制中最常用的几个函数

4.1 resize():改变元素数量

4.2 reserve():预留内存容量

4.3 resize() 和 reserve() 的本质区别

(1)resize(n)

(2)reserve(n)

4.4 clear():清空元素

4.5 shrink_to_fit():请求缩容

五、为什么vector效率高,但扩容也会有开销

六、动态扩容实验分析

6.1 这段代码的思路是什么

6.2 这段代码优化

6.3 为什么vector不会每次只扩1个空间

七、本节重点总结

7.1 size() 和 capacity() 的区别

7.2 resize() 和 reserve() 的区别

7.3 clear() 和 shrink_to_fit() 的区别

7.4 vector效率的本质

八、小结


一、前言

在前面的几篇内容中,我们已经学习了vector的基础使用,包括:

  • vector的定义与初始化
  • 元素访问与遍历
  • 搜索、删除、插入与排序

到这里,你已经知道vector是一个非常好用的动态数组容器。但如果想真正理解它为什么适合工程开发,仅仅会“用”还不够,还要进一步理解它背后的两个重要概念:

元素数量内存容量

很多初学者在学习vector时,最容易把下面这两个概念混在一起:

  • size()
  • capacity()

表面上看,它们都和“大小”有关,但其实它们表示的是两件完全不同的事情:

  • size():当前已经存了多少个元素
  • capacity():当前已经分配了多少个元素位置的内存容量

这两个概念搞清楚之后,你才会真正理解:

  • 为什么push_back()有时候很快,有时候会慢一点
  • 为什么clear()后元素没了,但内存不一定立刻变小
  • 为什么reserve()可以提前提高效率
  • 为什么resize()reserve()虽然都能“变大”,但本质完全不同

本节我们就结合代码,系统讲清楚vector的元素空间与内存空间显示和控制。


二、本节代码示例

先把本节要分析的核心代码放出来:

#include <iostream> #include <vector> using namespace std; int main() { vector<int> v1; vector<int> vdata(10); // 查看元素数量 cout << "v1.size():" << v1.size() << endl; cout << "vdata.size():" << vdata.size() << endl; // 查看容量大小 cout << "v1.capacity():" << v1.capacity() << endl; cout << "vdata.capacity():" << vdata.capacity() << endl; // resize:改变元素数量 v1.resize(8); // reserve:预留容量 v1.reserve(16); cout << "after resize and reserve\n"; cout << "v1.size():" << v1.size() << endl; cout << "v1.capacity():" << v1.capacity() << endl; // push_back:尾部新增元素 v1.push_back(99); for (auto v : v1) cout << v << "|"; cout << endl; // clear:清空元素 v1.clear(); cout << "after clear\n"; cout << "v1.size():" << v1.size() << endl; cout << "v1.capacity():" << v1.capacity() << endl; // shrink_to_fit:尝试缩容 v1.shrink_to_fit(); cout << "after shrink_to_fit\n"; cout << "v1.size():" << v1.size() << endl; cout << "v1.capacity():" << v1.capacity() << endl; cout << "----------------\n"; // 观察动态扩容 int c = v1.capacity(); for (int i = 0; i < 200; i++) { v1.push_back(i); if (c != v1.capacity()) { cout << "capacity from " << c << " to " << v1.capacity() << endl; c = v1.capacity(); } } return 0; }

这段代码虽然不长,但里面把vector的很多关键机制都串起来了,非常适合用来理解vector的空间管理逻辑。


三、什么是vector的元素空间和内存空间

3.1 元素空间:已经真正存在的元素个数

vector中所谓的“元素空间”,可以先理解为:

当前容器里真正已经存在、可以访问的元素数量

这个数量通过:

v.size()

来查看。

例如:

vector<int> v1; vector<int> vdata(10);

此时:

cout << "v1.size():" << v1.size() << endl; cout << "vdata.size():" << vdata.size() << endl;

输出为:

v1.size():0 vdata.size():10

说明:

  • v1现在一个元素都没有
  • vdata现在已经有 10 个元素了

也就是说,size()关心的是:

逻辑上有多少个元素存在。


3.2 内存空间:已经分配好的容量大小

vector还有一个很重要的概念叫容量,通过:

v.capacity()

来查看。

例如:

cout << "v1.capacity():" << v1.capacity() << endl; cout << "vdata.capacity():" << vdata.capacity() << endl;

输出为:

v1.capacity():0 vdata.capacity():10

这里表示:

  • v1当前没有元素,也没有额外分配存储空间
  • vdata当前不仅有 10 个元素,而且已经分配了足够容纳 10 个元素的内存

所以capacity()关心的是:

当前底层已经分配了多少“可容纳元素的位置”。


3.3 一定要区分:size不是capacity

这是本节最核心的地方。

size()capacity()的区别可以直接理解为:

(1)size()

当前已经存储的元素数量

(2)capacity()

当前已经分配好的内存容量,表示最多还能在不重新扩容的情况下容纳多少元素

比如:

vector<int> v; v.resize(8); v.reserve(16);

此时:

  • size()可能是 8
  • capacity()可能是 16

意思就是:

  • 现在真正存在 8 个元素
  • 但底层已经预留了 16 个元素的位置

也就是说,后面再继续插入一些元素时,只要不超过 16,就不需要重新申请内存


3.4 capacity显示的不是字节数

这里还要特别提醒一下:

capacity()返回的不是“字节数”,而是:

能容纳多少个当前类型的元素。

例如:

vector<int> v; v.reserve(16);

这里capacity()返回的是 16,不是 64。

虽然对于int来说,如果每个int占 4 字节,那么底层大致可能需要 16 × 4 = 64 字节左右的空间,但capacity()本身显示的是“元素个数容量”,不是字节数


四、vector空间控制中最常用的几个函数

4.1 resize():改变元素数量

代码:

v1.resize(8);

这句的作用是:

v1的元素数量改成 8。

因为v1原来是空的,所以执行完后,v1中就会真正出现 8 个元素。

对于int类型,这些新元素通常会被默认初始化为0

所以执行完后,v1的逻辑状态大致是:

0 0 0 0 0 0 0 0

此时:

  • v1.size()为 8
  • v1.capacity()至少也要能容纳 8 个元素

所以resize()的关键点是:

它不只是调整内存,更重要的是调整“元素个数”。


4.2 reserve():预留内存容量

代码:

v1.reserve(16);

这句的作用是:

至少把底层容量扩充到 16。

但是要注意:

reserve()只影响容量,不影响当前元素数量。

也就是说,如果原来:

  • size() = 8
  • capacity() = 8

执行:

v1.reserve(16);

之后通常会变成:

  • size() = 8
  • capacity() = 16

所以reserve()的本质是:

提前申请好内存,避免后续频繁扩容。

这在工程里非常常用,因为它可以减少反复申请和搬移内存带来的性能开销。


4.3 resize() 和 reserve() 的本质区别

这是非常容易考、也非常容易写错的点。

(1)resize(n)

改变的是元素数量

  • 如果变大,会新增元素
  • 如果变小,会删掉多余元素

(2)reserve(n)

改变的是容量大小

  • 只保证底层内存至少够大
  • 不会新增元素
  • 不会改变size()

可以直接记一句:

resize管“有几个元素”,reserve管“底下准备多大空间”。


4.4 clear():清空元素

代码:

v1.clear();

这句的作用是:

清空所有元素。

执行后:

  • size()会变成 0

但是要特别注意:

clear() 不保证释放底层容量。

也就是说,元素没了,不代表容量一定也归零。

比如清空前如果:

  • size() = 9
  • capacity() = 16

那么清空后很可能变成:

  • size() = 0
  • capacity() = 16

因为它只是把元素删除了,但底层那块内存还可能保留着,方便后续继续使用


4.5 shrink_to_fit():请求缩容

代码:

v1.shrink_to_fit();

这句的作用通常理解为:

  • 让容器尽量把多余容量缩掉,使容量更贴近当前元素数量.
  • 内存适应元素 有多少元素就分配多少内存

例如当前:

  • size() = 0
  • capacity() = 16

执行:

v1.shrink_to_fit();

之后很多实现中可能会变成:

  • size() = 0
  • capacity() = 0

但这里一定要严谨一点说明:

shrink_to_fit()是“请求缩容”,不是“强制必须缩到多少”。

调用shrink_to_fit()后,容器会尝试释放多余内存,使容量更贴近当前元素数量。


五、为什么vector效率高,但扩容也会有开销

这是理解vector性能的关键。

vector之所以访问快,是因为它底层通常是连续内存空间,和普通数组很像,所以支持:

  • 下标访问快
  • 遍历效率高
  • CPU 缓存友好

但是vector在不断push_back()时,并不是每加一个元素就只做一件小事。

如果当前容量已经满了,就会发生:

(1)重新申请一块更大的内存

(2)把原来元素搬过去

(3)释放旧内存

(4)再插入新元素

这个过程就叫扩容

所以vector的效率特点可以总结为:

  • 平时访问很快
  • 尾插一般也很快
  • 但一旦扩容,会有额外开销

这也是为什么:

如果你提前知道大概要放多少数据,最好先用reserve()预留空间。


六、动态扩容实验分析

后面这段代码,就是专门用来观察容量变化的:

int c = 0; //元素空间动态变化 for (int i = 0; i < 200; i++) { v1.push_back(i); if (c != v1.capacity()) { cout << "v1.capacity():" << c << endl; } c = v1.capacity(); }

这段代码的核心目的,是想观察:

随着元素不断增加,vector的容量是如何变化的。


6.1 这段代码的思路是什么

(1)不断push_back(i)

v1里的元素越来越多

(2)每插入一次,就检查当前容量是否变化

如果容量变化了,说明刚刚发生了扩容

(3)把扩容过程打印出来

这样就能看到vector不是每次只增加 1 个容量,而是会按某种增长策略扩容


6.2 这段代码优化

原代码里写的是:

if (c != v1.capacity()) { cout << "v1.capacity():" << c << endl; } c = v1.capacity();

这里打印的是旧值c,不是变化后的新容量。

所以如果想让观察更直观,建议改成:

int c = v1.capacity(); for (int i = 0; i < 200; i++) { v1.push_back(i); if (c != v1.capacity()) { cout << "capacity from " << c << " to " << v1.capacity() << endl; c = v1.capacity(); } }

这样输出会更清楚,比如类似:

capacity from 0 to 1 capacity from 1 to 2 capacity from 2 to 4 capacity from 4 to 8 capacity from 8 to 16 ...

当然,不同编译器、不同标准库实现,扩容策略可能略有不同,但通常都不是“每次只加1”。


6.3 为什么vector不会每次只扩1个空间

如果每次插入一个元素,都只扩容 1 个位置,那么会频繁发生:

  • 申请内存
  • 拷贝旧数据
  • 释放旧空间

这样效率会非常差

所以vector通常会采用一种“按比例增长”的方式,例如:

  • 扩到 2 倍
  • 或者扩到更大的某个倍数

这样就能减少扩容次数,提高整体效率。

这也是vector性能设计里非常重要的一点。


七、本节重点总结

7.1 size() 和 capacity() 的区别

(1)size()

当前真正存在的元素个数

(2)capacity()

当前底层已分配好的容量大小


7.2 resize() 和 reserve() 的区别

(1)resize(n)

改变元素数量
会真正新增或删除元素

(2)reserve(n)

改变容量大小
只扩内存,不新增元素


7.3 clear() 和 shrink_to_fit() 的区别

(1)clear()

清空元素,但不一定释放容量

(2)shrink_to_fit()

尝试缩小容量,使其更贴近当前元素数量


7.4 vector效率的本质

(1)访问快,因为底层是连续空间

(2)尾插通常也快

(3)扩容时会有额外开销

(4)提前reserve()可以减少扩容次数,提高效率


八、小结

本节我们从“能不能用 vector”,进一步走到了“vector 为什么这么设计”。

vector 不仅在管理元素,还在管理一块可动态变化的连续内存空间。

也正因为如此,学习vector时一定要分清两件事:

  • 现在有多少元素
  • 现在底层预留了多少空间
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 22:58:15

QQ空间说说备份终极指南:5分钟快速导出所有历史记录

QQ空间说说备份终极指南&#xff1a;5分钟快速导出所有历史记录 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory GetQzonehistory是一款完全免费的Python开源工具&#xff0c;专为QQ空间…

作者头像 李华
网站建设 2026/4/20 22:57:16

ETH苏黎世突破:AI医疗配备实时监考系统实现推理准确率提升25%

这项由瑞士苏黎世联邦理工学院&#xff08;ETH Zrich&#xff09;与德国海德堡大学联合开展的研究&#xff0c;以预印本形式发布于2026年4月&#xff0c;论文编号为arXiv:2604.09482。对完整技术细节感兴趣的读者可通过该编号检索原文。**一段不可忽视的背景故事**设想一位主治…

作者头像 李华
网站建设 2026/4/20 22:55:14

AI Agent的自主性与可控性平衡:安全对齐的关键挑战

AI Agent的自主性与可控性平衡:安全对齐的关键挑战 1. 引言 在人工智能技术飞速发展的今天,我们正站在一个新时代的门槛上。从早期的专家系统到如今的大型语言模型(LLMs),AI已经从简单的工具演变为能够自主决策和行动的智能体(Agent)。这些AI Agent不再仅仅执行预定义的…

作者头像 李华
网站建设 2026/4/20 22:51:16

3分钟解决Minecraft模组英文难题:MASA全家桶汉化包完整指南

3分钟解决Minecraft模组英文难题&#xff1a;MASA全家桶汉化包完整指南 【免费下载链接】masa-mods-chinese 一个masa mods的汉化资源包 项目地址: https://gitcode.com/gh_mirrors/ma/masa-mods-chinese 你是否曾在Minecraft中面对Litematica、Minihud等MASA模组的英文…

作者头像 李华