<vector>
在 C++ 中,vector是标准库(STL)提供的动态数组容器,属于序列容器的一种。它结合了静态数组的高效随机访问特性与动态扩容能力,是日常开发中最常用的容器之一。本文将详细解析其实现原理与常见操作。
vector 概述
vector本质是动态数组,支持在运行时动态调整大小。其核心特点包括:
- 元素在内存中连续存储,支持随机访问(时间复杂度 O (1));
- 尾部插入 / 删除元素效率高(不扩容时 O (1));
- 中间插入 / 删除元素效率低(需移动后续元素,O (n));
- 自动管理内存,无需手动分配 / 释放。
使用前需包含头文件:#include <vector>,且位于std命名空间中。
vector 实现原理
<vector>已经十分成熟有几千行代码,熟悉使用即可,以下仅方便理解,不是原代码。
vector的底层通过动态分配的数组存储元素,并通过三个核心指针管理内存:
- begin:指向数组中第一个元素的地址;
- end:指向数组中最后一个元素的下一个位置(即当前元素末尾);
_end_of_storage:指向数组内存块的末尾(即容量末尾)。
通过这三个指针可快速计算:
- 大小(
size):end - begin(当前元素个数); - 容量(
capacity):_end_of_storage - begin(当前可容纳的最大元素数)。
包含大小和容量的简化版
template<typename T>
class vector {
private:
T* data; // 指向动态数组的指针
size_t size; // 当前元素数量
size_t capacity; // 当前分配的内存容量
};
现在忘掉之前的一切,只记住简化版即可
动态扩容机制
当插入元素导致size超过capacity时,vector会触发扩容,步骤如下:
- 分配新内存:新容量通常为原容量的 1.5 倍(VS 编译器)或 2 倍(GCC 编译器);
- 复制元素:将原数组元素复制(或移动)到新内存;
- 释放旧内存:销毁原数组元素并释放旧内存;
- 更新指针:指向新内存的对应位置。
注意:扩容后,原有的迭代器、指针、引用会失效(内存地址已改变)。
常见操作详解
1. 创建与初始化
vector支持多种初始化方式,适应不同场景:
| 方式 | 示例 | 说明 |
|---|---|---|
| 默认构造 | vector<int> v; | 空 vector,size=0,capacity=0 |
| 指定大小与初始值 | vector<int> v(5, 10); | 5 个元素,每个值为 10(size=5,capacity=5) |
| 数组初始化 | int arr[] = {1,2,3}; vector<int> v(arr, arr+3); | 用数组 [arr, arr+3) 范围初始化 |
| 拷贝构造 | vector<int> v2(v1); | 复制 v1 的所有元素(深拷贝) |
| 移动构造 | vector<int> v2 = move(v1); | 转移 v1 的资源(v1 此后为空) |
| 列表初始化 | vector<int> v{1,2,3,4}; | 用初始化列表直接赋值(C++11) |
2. 元素访问
vector提供多种访问元素的方式,各有特点:
| 操作 | 示例 | 说明 |
|---|---|---|
operator[] | v[2] = 10; | 访问索引为 2 的元素,不检查越界(越界行为未定义) |
at() | v.at(2) = 10; | 访问索引为 2 的元素,越界时抛出out_of_range异常 |
front() | int x = v.front(); | 返回第一个元素的引用(容器非空) |
back() | int y = v.back(); | 返回最后一个元素的引用(容器非空) |
data() | int* p = v.data(); | 返回指向底层数组的指针(可直接操作原始数组) |
3. 修改操作
修改操作主要用于添加、删除或替换元素:
| 操作 | 示例 | 说明 |
|---|---|---|
push_back(val) | v.push_back(5); | 在尾部添加元素 val(可能触发扩容) |
emplace_back(args...) | v.emplace_back(5); | 在尾部直接构造元素(避免拷贝,比push_back高效) |
pop_back() | v.pop_back(); | 删除尾部元素(size 减 1,capacity 不变) |
insert(pos, val) | v.insert(v.begin()+1, 10); | 在迭代器 pos 前插入 val,返回新元素的迭代器(可能扩容,pos 后迭代器失效) |
erase(pos) | auto it = v.erase(v.begin()); | 删除 pos 位置的元素,返回下一个元素的迭代器(pos 后迭代器失效) |
clear() | v.clear(); | 清空所有元素(size=0,但 capacity 不变) |
4. 容量操作
容量操作用于管理vector的内存使用:
| 操作 | 示例 | 说明 |
|---|---|---|
size() | int s = v.size(); | 返回当前元素个数 |
capacity() | int c = v.capacity(); | 返回当前可容纳的最大元素数 |
empty() | if (v.empty()) { ... } | 判断是否为空(size==0) |
reserve(n) | v.reserve(10); | 预留容量为 n(若 n > 当前 capacity 则扩容,不改变 size) |
resize(n, val) | v.resize(5, 0); | 调整 size 为 n(n > 原 size 则补 val;n < 原 size 则删除多余元素,可能改变 capacity) |
shrink_to_fit() | v.shrink_to_fit(); | 缩减 capacity 至与 size 相等(C++11,释放多余内存) |
5. 迭代器
迭代器是访问vector元素的通用方式,支持遍历、插入、删除等操作:
| 迭代器类型 | 示例 | 说明 |
|---|---|---|
| 正向迭代器 | begin() / end() | 遍历元素(从第一个到最后一个的下一个) |
| 反向迭代器 | rbegin() / rend() | 反向遍历(从最后一个到第一个的前一个) |
| const 迭代器 | cbegin() / cend() | 只读访问(不允许修改元素) |
迭代器失效场景:
- 扩容时:所有迭代器、指针、引用失效;
insert插入元素后:插入位置后的迭代器失效;erase删除元素后:删除位置后的迭代器失效(返回的新迭代器有效)。
总结
vector是 C++ 中最常用的动态数组容器,通过连续内存存储和动态扩容机制,平衡了效率与灵活性。掌握其实现原理(三个核心指针、扩容机制)和常见操作(初始化、访问、修改、容量管理),能帮助开发者更高效地使用vector,避免因迭代器失效或不当扩容导致的问题。

浙公网安备 33010602011771号