目录
为什么有std::vector
?
int arr[10]; // 固定大小数组
这个东西用起来很简单,但它有几个硬伤:
-
大小固定:你不能动态增加元素。
-
不能自动扩容:想插入第 11 个元素?麻烦了。
-
没有安全边界检查:
arr[100]
也不会报错,直接 UB(undefined behavior)。 -
不能直接赋值、复制、比较。
-
缺少高级接口:没有
.size()
、.push_back()
、.insert()
等等。
于是,我们问一个根本性的问题:
有没有一个可以自动扩容、安全、易用、功能丰富的“数组”?
C++ 标准库说:有,那就是 —— std::vector
什么是 std::vector
?
std::vector<T>
是 C++ 标准库提供的一个 动态数组模板类,能在运行时自动管理内存、调整大小、提供各种操作方法。
你可以理解它是 C++ 中的“可变长数组”,但背后封装了大量复杂逻辑。
vector 的核心设计理念(用类思维理解)
template<typename T>
class vector {
private:
T* data; // 元素数组(堆上分配)
size_t size; // 当前元素个数
size_t capacity; // 当前分配的最大容量
public:
void push_back(const T& val);
void pop_back();
void resize(size_t new_size);
void reserve(size_t new_capacity);
T& operator[](size_t index);
size_t size() const;
// ...
};
vector 就是自己在内部维护了一个 堆上的数组,并且提供各种方法自动管理这块内存。
动态数组的底层结构
std::vector
内部就像是这样:
[ 0 ][ 1 ][ 2 ][ 3 ][ 4 ] ← 一整块连续内存
动态数组背后的核心思想是,当数组容量用尽时,它会自动扩展。这是通过以下几个步骤实现的:
-
初始分配内存:当你创建一个动态数组时,它会分配一块初始的内存空间。例如,在 C++ 中,
std::vector
默认会分配一个固定的大小(比如 0 或 1)。 -
增加元素时的扩展机制:当数组中的元素超出当前分配的空间时,动态数组会进行扩展。常见的做法是将数组的容量增加为原来的两倍。这样,数组容量的增加会使得扩容的次数减少,从而提升性能。
-
元素复制和内存释放:扩容时,程序会申请一个新的更大的内存块,然后将旧数组中的元素复制到新数组中。最后,释放掉旧数组的内存。
-
删除元素时的收缩机制:虽然扩展通常是自动的,但收缩则不总是自动进行的。在某些情况下,动态数组可能会减少其容量以释放内存,特别是在元素数量显著减少时。
-
所有元素挨在一起
-
优点:随机访问非常快(因为地址是线性的)
-
缺点:
-
如果你在开头插入一个元素,就要把所有元素后移 → 开销大
-
动态数组的基本操作
操作 | 功能 | 底层发生了什么 |
---|---|---|
push_back(x) | 尾部添加元素 | 空间足够就加,不够就扩容 |
pop_back() | 删除最后一个元素 | 只是 size-- ,不释放内存 |
size() | 返回当前元素个数 | O(1),不等于 capacity() |
capacity() | 返回总容量 | 看看当前还能装多少 |
reserve(n) | 预留容量 | 提前分配内存,避免频繁扩容 |
resize(n) | 修改逻辑大小 | 增大则构造新元素,减小则析构多余 |
clear() | 清空元素 | size = 0 ,但内存还在 |
operator[] | 访问元素 | 没有边界检查,风险! |
at(i) | 访问元素 | 有边界检查,超出抛异常 |
创建和初始化
#include <iostream>
#include <vector>
int main() {
// 创建一个空的动态数组
std::vector<int> arr;
// 创建一个指定大小和初始值的动态数组
std::vector<int> arr2(5, 10); // 创建一个包含5个元素,每个元素初始值为10的数组
// 创建一个带有初始值的动态数组
std::vector<int> arr3 = {1, 2, 3, 4, 5};
// 输出 arr3 的内容
for (int i = 0; i < arr3.size(); ++i) {
std::cout << arr3[i] << " ";
}
return 0;
}
插入元素
#include <iostream>
#include <vector>
int main() {
std::vector<int> arr;
// 向数组末尾添加元素
arr.push_back(10);
arr.push_back(20);
arr.push_back(30);
// 输出数组内容
for (int i = 0; i < arr.size(); ++i) {
std::cout << arr[i] << " ";
}
return 0;
}
删除元素
#include <iostream>
#include <vector>
int main() {
std::vector<int> arr = {10, 20, 30};
// 删除最后一个元素
arr.pop_back();
// 输出删除后的数组内容
for (int i = 0; i < arr.size(); ++i) {
std::cout << arr[i] << " ";
}
return 0;
}
访问元素
#include <iostream>
#include <vector>
int main() {
std::vector<int> arr = {10, 20, 30};
// 使用下标访问元素
std::cout << "First element: " << arr[0] << std::endl;
// 使用 at() 方法访问元素(带边界检查)
std::cout << "Second element: " << arr.at(1) << std::endl;
return 0;
}
容量与大小
#include <iostream>
#include <vector>
int main() {
std::vector<int> arr = {10, 20, 30};
// 获取元素个数
std::cout << "Size: " << arr.size() << std::endl;
// 获取容量(当前能够容纳的元素个数)
std::cout << "Capacity: " << arr.capacity() << std::endl;
return 0;
}
插入特定位置的元素:
使用 insert()
方法可以在特定位置插入元素。例如:
arr.insert(arr.begin() + 1, 15); // 在索引为1的位置插入15
删除指定位置的元素:
使用 erase()
方法可以删除特定位置的元素。
arr.erase(arr.begin() + 1); // 删除索引为1的元素
清空数组:
使用 clear()
方法可以删除所有元素,清空数组。
arr.clear();
调整容量:
1.reserve()
方法
用于预先分配至少 n
个元素的空间。它不会改变当前存储的元素个数(即数组的 size()
),但会确保至少有 n
个元素的内存空间可用。如果当前容量小于 n
,则会分配更多的内存。如果 n
小于或等于当前容量,则不会做任何操作。
vector.reserve(n);
n
:指定所需的最小容量。这个容量是指 vector
至少能够容纳 n
个元素,而不需要重新分配内存。
注意: reserve()
只是调整容量,而不会影响 size()
,所以它不会增加现有元素的数量。
示例:
#include <iostream>
#include <vector>
int main() {
std::vector<int> arr;
// 初始容量为0,reserve(10)会将容量预留为至少10个元素
arr.reserve(10);
// 检查容量
std::cout << "Capacity after reserve: " << arr.capacity() << std::endl;
// 向数组中添加元素
arr.push_back(1);
arr.push_back(2);
// 检查大小和容量
std::cout << "Size: " << arr.size() << ", Capacity: " << arr.capacity() << std::endl;
return 0;
}
输出:
Capacity after reserve: 10
Size: 2, Capacity: 10
2.shrink_to_fit()
方法
请求将 std::vector
的容量减少到与当前 size()
相等。即它会释放多余的内存空间,优化内存使用。需要注意的是,shrink_to_fit()
只是一个请求操作,实际是否进行内存调整取决于实现,可能并不会立刻发生。
语法:
vector.shrink_to_fit();
注意:shrink_to_fit()
并不会直接改变 size()
,它只会尝试调整 vector
的容量,使其更接近当前的元素数量。
示例:
#include <iostream>
#include <vector>
int main() {
std::vector<int> arr;
// 添加一些元素
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
// 查看当前容量
std::cout << "Before shrink: Size = " << arr.size() << ", Capacity = " << arr.capacity() << std::endl;
// 调用 shrink_to_fit() 请求减少容量
arr.shrink_to_fit();
// 查看调用后的大小和容量
std::cout << "After shrink: Size = " << arr.size() << ", Capacity = " << arr.capacity() << std::endl;
return 0;
}
输出:
Before shrink: Size = 3, Capacity = 4
After shrink: Size = 3, Capacity = 3
终极总结一句话:
vector
是 C++ 提供的“自动化动态数组”,本质是用堆内存 + 封装管理 + 自动扩容,实现了内存安全与操作便利的平衡。