vector动态数组

动态数组就是由用户申请的一块连续的动态内存,封装了相关的操作接口之后就成了vector。

1、vector 动态数组 和 静态数组的区别?
维度 静态数组(C-style / std::array) 动态数组(std::vector)
内存位置 栈(或全局区)
大小 编译期固定 运行期动态增长
扩容 不支持 自动扩容(2倍或1.5倍)
底层 连续内存块 连续内存块 + 三个指针

核心共性 :两者都是连续内存,支持 O(1) 随机访问。

2、 vector 的三指针模型?
复制代码
┌─────────────────────────────────────────┐
│  _M_start  →  指向首元素                 │
│  _M_finish →  指向最后一个元素的下一个位置  │
│  _M_end_of_storage →  指向分配内存的末尾   │
└─────────────────────────────────────────┘

  [a][b][c][d][ ][ ][ ][ ]  
   ↑           ↑           ↑
 start      finish    end_of_storage
        size=4      capacity=8
3、vector的扩容机制?

当调用push_back 函数插入元素,vector内存空间不足时,引发扩容机制。

(1)申请新的内存空间(一般是原内存空间的2倍,VS是1.5倍)。

(2)将原内存空间内的数据拷贝到新的内存空间。

(3)释放旧内存空间。

cpp 复制代码
// 当 size == capacity,再 push_back 时:
void push_back(const T& val) {
    if (finish != end_of_storage) {
        // 有空间,直接构造
        construct(finish, val);
        ++finish;
    } else {
        // 没空间 → 扩容
        size_t new_capacity = (capacity() == 0) ? 1 : capacity() * 2; // GCC: 2倍; VS: 1.5倍
        T* new_start = allocate(new_capacity);
        
        // 把旧元素搬过去(浅拷贝 or 移动构造)
        for (size_t i = 0; i < size(); ++i) {
            new_start[i] = std::move(old_start[i]);
        }
        deallocate(old_start);  // 释放旧内存
        // 更新三个指针
    }
}

扩容时,所有指向元素的迭代器、指针和引用确实会全部失效。扩容时vector 会申请一块更大的新内存,将原有元素拷贝或移动到新内存中,然后释放旧内存。任何指向旧内存的"地址"都成了悬垂指针,继续使用将导致未定义行为。即使没有触发扩容push_back 等操作也会使 end() 迭代器失效。例如:

cpp 复制代码
std::vector<int> v;
v.reserve(10);          // 预留空间,capacity = 10
auto it = v.end();      // 指向末尾(此时末尾是begin)
v.push_back(1);         // 未扩容,size 从 0 变 1
// it 仍然指向"末尾",但现在末尾已经变成元素1之后了
// 实际上 it 已失效,不能再用它去访问元素1
4、vector 的 push_back 和 emplace_back 区别?
cpp 复制代码
v.push_back(MyClass(1, 2));   // 构造临时对象 → 拷贝/移动进 vector
v.emplace_back(1, 2);         // 直接在 vector 内存里构造,零拷贝

push_back()它会先创建一个临时 MyClass 对象(在栈上或寄存器中)。 然后将这个临时对象移动或拷贝到 vector 中(默认会先进行移动,对象不支持移动构造时触发拷贝,如果连拷贝构造也不支持,那么就会编译失败)。

5、vector 扩容后迭代器为什么失效?

扩容会重新分配内存并把旧内存的元素搬过去,旧内存被释放。原来指向旧地址的迭代器/指针就变成了悬空指针,访问会产生未定义行为报错。

cpp 复制代码
vector<int> v = {1, 2, 3};
auto it = v.begin();
v.push_back(4);  // 可能扩容
// it 此时已失效!不能再使用
6、reserve 和 resize 的区别?
reserve(n) resize(n)
改变 size ❌ 不改变 ✅ 改变
改变 capacity ✅ 可能增大 ✅ 可能增大
构造元素 ❌ 不构造 ✅ 构造 n 个元素
用途 预分配,避免扩容 改变实际元素个数
cpp 复制代码
vector<int> v;
v.reserve(100);  // capacity=100, size=0, 没有元素
v.resize(100);   // capacity=100, size=100, 100个0
7、vector 底层是连续内存,怎么证明?
cpp 复制代码
// 1. &v[i+1] - &v[i] == 1,地址连续
// 2. vector 可以兼容 C 接口:&v[0] 或 v.data()
void c_func(int* arr, size_t n);
c_func(v.data(), v.size());  // 可以直接传
8、为什么 vector 的 operator\[\] 不检查越界,at() 会?
cpp 复制代码
v[10];    // 不检查,越界 → 未定义行为,但快
v.at(10); // 抛 std::out_of_range 异常,安全

追求零开销抽象(和 C 数组一致),at() 提供安全版本。面试时可以补充:自己写库代码用 at(),写性能敏感代码用

9、vector 内存什么时候释放?clear() 会释放吗?

clear() 只析构元素,不改变 capacity,内存不释放

shrink_to_fit() 请求缩减到 size(但标准说"请求",执行可能会不成功,执行原理是重新申请一块新内存,然后将旧数据拷贝过去,再)

真正释放:vector 析构时,或 vector<T>().swap(v) 这个经典技巧

相关推荐
hetao173383715 分钟前
2026-09-01~09-04 hetao1733837 的刷题记录
c++·算法
Evand J33 分钟前
【MATLAB例程,图像滤波5】 反谐波均值滑动窗口滤波(CHMF)图像降噪与质量评价,附代码下载链接
图像处理·算法·计算机视觉·matlab·均值算法·滑动窗口滤波·均值滑动
血小板要健康1 小时前
链表 阶段算法总结
java·数据结构·笔记·算法·leetcode·链表
a187927218311 小时前
【算法】回溯算法(三):三记重锤与 N 皇后——记忆化、状态设计与三层漏斗
算法·leetcode·go·剪枝·回溯·n皇后·算法讲解
HugoStudio_SWAN3 小时前
洛谷 P1420 / P1179 / B4262 最长连号、数字统计与词频统计——统计的三种面孔
c++·学习·程序人生·算法
青 春 记 忆4 小时前
LeetCode 350. 两个数组的交集 II|Python 解法详解
python·算法·leetcode
阳明山水4 小时前
销量预测2025—2026:从模型竞赛到系统融合的范式转型
人工智能·深度学习·算法·机器学习·架构
桐盛科技5 小时前
拒绝“漂绿”风险:基于边缘计算的碳排放数据清洗算法与实时校验逻辑
人工智能·算法·边缘计算
Tongzhi20265 小时前
通芝科技考勤软件三大发展趋势:AI大模型、无感识别与数据底座
大数据·科技·算法·爬山算法
eBest数字化转型方案5 小时前
Route Optimization for FMCG:多目标排线算法的工程实现
大数据·人工智能·算法