C++从入门到实战(十九)C++ vector容器及其常用接口
- 前言
- 一、什么是vector
- 二、vector的构造接口
- 
- [1. 默认构造函数:创建空vector](#1. 默认构造函数:创建空vector)
- [2. 带大小的构造:创建指定长度的vector](#2. 带大小的构造:创建指定长度的vector)
- [3. 带大小和初始值的构造:指定长度+统一初始值](#3. 带大小和初始值的构造:指定长度+统一初始值)
- [4. 迭代器范围构造:从其他容器复制元素](#4. 迭代器范围构造:从其他容器复制元素)
- [5. 拷贝构造:复制已有vector](#5. 拷贝构造:复制已有vector)
- [6. 列表初始化(C++11起):直接指定元素](#6. 列表初始化(C++11起):直接指定元素)
- 总结:vector构造方式对比
 
- 三、vector的遍历方法
- 
- [1. 下标访问(operator[])](#1. 下标访问(operator[]))
- [2. at() 访问(安全版下标)](#2. at() 访问(安全版下标))
- [3. 迭代器遍历(重点掌握)](#3. 迭代器遍历(重点掌握))
- 
- [3.1 正向迭代器(begin()` / `end()`)](#3.1 正向迭代器(begin()/end()`))
- [3.2 反向迭代器(`rbegin()` / `rend()`)](#3.2 反向迭代器(rbegin()/rend()))
- [3.3 const迭代器(只读访问)](#3.3 const迭代器(只读访问))
 
- [3.1 正向迭代器(begin()` / `end()`)](#3.1 正向迭代器(begin()
- [4. 范围for循环(C++11起,最简洁)](#4. 范围for循环(C++11起,最简洁))
- 总结:遍历方式对比
 
- 四、vector的容量管理
- 
- [1. size():获取实际元素个数](#1. size():获取实际元素个数)
- [2. capacity():获取当前分配的容量](#2. capacity():获取当前分配的容量)
- [3. empty():判断是否为空](#3. empty():判断是否为空)
- [4. reserve(n):预分配容量](#4. reserve(n):预分配容量)
- [5. resize(n) / resize(n, val):调整大小](#5. resize(n) / resize(n, val):调整大小)
- [6. shrink_to_fit():释放多余内存](#6. shrink_to_fit():释放多余内存)
- [7. max_size():理论最大容量](#7. max_size():理论最大容量)
- 总结:容量管理核心接口
 
- 五、vector的元素修改
- 
- [1. push_back():尾部添加元素](#1. push_back():尾部添加元素)
- [2. pop_back():尾部删除元素](#2. pop_back():尾部删除元素)
- [3. insert():指定位置插入元素](#3. insert():指定位置插入元素)
- [4. erase():删除指定位置元素](#4. erase():删除指定位置元素)
- [5. swap():交换两个vector](#5. swap():交换两个vector)
- [6. clear():清空所有元素](#6. clear():清空所有元素)
 
前言
- 前面我们已经学习了C++中String的诸多知识点,了解了它作为动态字符串的特性与常用操作。
- 接下来,我们将探讨C++ STL中另一个核心容器------vector 。它与string在底层实现和接口设计上有诸多相似之处,但功能更通用:string专为字符设计,而vector可存储任意类型的数据。
- 本篇将深入解析vector的核心概念、构造方式、遍历方法及容量管理,为后续复杂容器的学习打下基础。
我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343我的C++知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_12880513.html?spm=1001.2014.3001.5482
C++官方vector文档
https://cplusplus.com/reference/vector/vector/
一、什么是vector
std::vector 是C++ STL(标准模板库)中的动态数组容器 ,可以理解为"能自动扩容的数组"。
- 与C语言的静态数组相比,vector无需手动指定大小,会根据元素数量自动调整内存空间。
- 与string相比,vector是模板类 (template <class T>),可存储任意类型(int、double、自定义对象等),而string仅存储char。
- 本质上,vector是"顺序表"的实现:元素在内存中连续存储,支持随机访问(通过下标快速访问任意元素)。
C++官方vector文档
https://cplusplus.com/reference/vector/vector/
二、vector的构造接口
vector提供了多种构造方式,可根据不同场景灵活初始化。以下是最常用的构造函数:
1. 默认构造函数:创建空vector
            
            
              cpp
              
              
            
          
          vector<T>();  // T为存储的元素类型(如int、string等)作用 :创建一个空的vector,不含任何元素,大小为0。
例子:
            
            
              cpp
              
              
            
          
          #include <vector>
#include <string>
#include <iostream>
using namespace std;
int main() {
    vector<int> v1;  // 空vector(存储int类型)
    vector<string> v2;  // 空vector(存储string类型)
    return 0;
}
2. 带大小的构造:创建指定长度的vector
            
            
              cpp
              
              
            
          
          vector<T>(size_t n);作用 :创建一个包含 n 个元素的vector,元素值为默认初始化(内置类型为0,自定义类型调用默认构造)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v(5);  // 包含5个int,默认值为0
for (int num : v) {
    cout << num << " ";  // 输出:0 0 0 0 0
}
3. 带大小和初始值的构造:指定长度+统一初始值
            
            
              cpp
              
              
            
          
          vector<T>(size_t n, const T& val);作用 :创建包含 n 个元素的vector,每个元素的值均为 val。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v(3, 10);  // 3个元素,每个都是10
for (int num : v) {
    cout << num << " ";  // 输出:10 10 10
}
4. 迭代器范围构造:从其他容器复制元素
            
            
              cpp
              
              
            
          
          template <class InputIterator>
vector<T>(InputIterator first, InputIterator last);作用 :复制另一个容器(如vector、string、数组)中 [first, last) 范围内的元素。
例子:
            
            
              cpp
              
              
            
          
          // 从数组构造
int arr[] = {1, 2, 3, 4};
vector<int> v1(arr, arr + 4);  // 复制arr的所有元素
// 从另一个vector构造
vector<int> v2(v1.begin(), v1.end());  // 复制v1的所有元素
for (int num : v2) {
    cout << num << " ";  // 输出:1 2 3 4
}
5. 拷贝构造:复制已有vector
            
            
              cpp
              
              
            
          
          vector<T>(const vector<T>& other);作用 :创建一个与 other 完全相同的vector(元素值和大小均一致)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v1 = {1, 2, 3};  // 初始化v1
vector<int> v2(v1);  // 拷贝构造,v2与v1相同
for (int num : v2) {
    cout << num << " ";  // 输出:1 2 3
}6. 列表初始化(C++11起):直接指定元素
            
            
              cpp
              
              
            
          
          vector<T> v = {a, b, c, ...};  // 或 vector<T> v{a, b, c, ...};作用 :用初始化列表中的元素直接构造vector,元素顺序与列表一致。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {10, 20, 30};  // 3个元素:10,20,30
vector<string> vs{"hello", "world"};  // 2个string元素
for (int num : v) {
    cout << num << " ";  // 输出:10 20 30
}
总结:vector构造方式对比
| 构造方式 | 语法示例 | 适用场景 | 
|---|---|---|
| 默认构造 | vector<int> v; | 初始为空,后续动态添加元素 | 
| 带大小构造 | vector<int> v(5); | 需要固定长度,元素默认初始化 | 
| 大小+初始值构造 | vector<int> v(3, 10); | 固定长度,元素值相同 | 
| 迭代器范围构造 | vector<int> v(arr, arr+4); | 从其他容器复制元素 | 
| 拷贝构造 | vector<int> v(other); | 复制已有vector | 
| 列表初始化(C++11) | vector<int> v{1,2,3}; | 已知初始元素,简洁直观 | 
三、vector的遍历方法
vector支持多种遍历方式,与string类似,核心是通过下标 、迭代器 或范围for访问元素。
1. 下标访问(operator[])
语法 :v[i](i 为索引,从0开始)
特点 :与数组用法一致,不检查越界(越界访问会导致未定义行为)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3, 4, 5};
for (size_t i = 0; i < v.size(); ++i) {
    cout << v[i] << " ";  // 输出:1 2 3 4 5
}
2. at() 访问(安全版下标)
语法 :v.at(i)
特点 :与 v[i] 功能相同,但会检查越界 (越界时抛出 out_of_range 异常)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
try {
    cout << v.at(2) << endl;  // 输出:3(合法访问)
    cout << v.at(5) << endl;  // 越界,抛出异常
} catch (const out_of_range& e) {
    cout << "错误:" << e.what() << endl;  // 捕获异常
}
3. 迭代器遍历(重点掌握)
迭代器是STL容器的通用访问方式,vector的迭代器用法与string几乎一致。
3.1 正向迭代器(begin()/end()`)
- begin():指向第一个元素的迭代器。
- end():指向最后一个元素下一个位置的迭代器(不包含元素)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
// 正向遍历
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
    cout << *it << " ";  // *it 访问当前元素,输出:1 2 3
}
简化写法(auto 自动推导类型):
            
            
              cpp
              
              
            
          
          for (auto it = v.begin(); it != v.end(); ++it) {
    cout << *it << " ";  // 效果同上
}3.2 反向迭代器(rbegin() / rend())
- rbegin():指向最后一个元素的反向迭代器。
- rend():指向第一个元素前一个位置的反向迭代器。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
// 反向遍历(从后往前)
for (vector<int>::reverse_iterator rit = v.rbegin(); rit != v.rend(); ++rit) {
    cout << *rit << " ";  // 输出:3 2 1
}
3.3 const迭代器(只读访问)
用于遍历const vector(或需要保证元素不被修改的场景):
- const_iterator:正向只读迭代器。
- const_reverse_iterator:反向只读迭代器。
例子:
            
            
              cpp
              
              
            
          
          const vector<int> cv = {1, 2, 3};  // const vector,元素不可修改
for (vector<int>::const_iterator it = cv.begin(); it != cv.end(); ++it) {
    // *it = 10;  // 错误!const迭代器不可修改元素
    cout << *it << " ";  // 输出:1 2 3
}
4. 范围for循环(C++11起,最简洁)
语法 :for (元素类型 变量 : vector名) { ... }
特点 :自动遍历所有元素,无需手动控制索引或迭代器。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
for (int num : v) {  // 依次取v中的元素赋值给num
    cout << num << " ";  // 输出:1 2 3
}
修改元素 :若需在范围for中修改元素,变量需用引用(&):
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
for (int& num : v) {  // 引用传递,可修改原元素
    num *= 2;
}
for (int num : v) {
    cout << num << " ";  // 输出:2 4 6
}总结:遍历方式对比
| 遍历方式 | 语法示例 | 优势 | 注意事项 | 
|---|---|---|---|
| 下标访问 | v[i] | 直观,与数组一致 | 不检查越界,需确保 i < v.size() | 
| at()访问 | v.at(i) | 越界时抛出异常,更安全 | 性能略低于下标访问 | 
| 迭代器遍历 | for (auto it = v.begin(); ...) | 支持STL算法(如sort),通用接口 | 注意迭代器失效问题 | 
| 范围for循环 | for (int num : v) | 代码简洁,适合简单遍历 | 需C++11及以上标准 | 
四、vector的容量管理
vector的容量管理与string类似,核心是区分大小(size) 和容量(capacity),并通过接口灵活控制内存。
1. size():获取实际元素个数
作用 :返回vector中当前元素的数量。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
cout << v.size() << endl;  // 输出:32. capacity():获取当前分配的容量
作用 :返回vector当前已分配的内存可容纳的最大元素数(容量 ≥ 大小)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v;
v.push_back(1);  // 添加一个元素
cout << v.size() << endl;     // 输出:1(实际元素数)
cout << v.capacity() << endl; // 输出:1(初始容量,不同编译器可能不同)
v.push_back(2);  // 再次添加元素
cout << v.capacity() << endl; // 输出:2(容量自动扩容)3. empty():判断是否为空
作用 :检查vector是否不含任何元素(size() == 0)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v1;
vector<int> v2 = {1};
cout << v1.empty() << endl;  // 输出:1(true,空)
cout << v2.empty() << endl;  // 输出:0(false,非空)
4. reserve(n):预分配容量
作用 :提前分配至少能容纳 n 个元素的内存(仅改变容量,不改变大小)。
目的 :减少后续添加元素时的扩容次数(扩容需复制旧元素,代价高)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v;
v.reserve(100);  // 预分配100个元素的容量
cout << v.size() << endl;     // 输出:0(大小不变)
cout << v.capacity() << endl; // 输出:100(容量变为100)
5. resize(n) / resize(n, val):调整大小
作用 :将vector的大小调整为 n:
- 若 n < 当前size():截断多余元素(保留前n个)。
- 若 n > 当前size():新增元素用val初始化(默认值:内置类型为0,自定义类型调用默认构造)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
v.resize(5, 10);  // 大小扩至5,新增元素为10
for (int num : v) {
    cout << num << " ";  // 输出:1 2 3 10 10
}
v.resize(2);  // 大小缩至2,截断多余元素
for (int num : v) {
    cout << num << " ";  // 输出:1 2
}6. shrink_to_fit():释放多余内存
作用 :将容量缩减至与大小相等,释放未使用的内存。
注意 :需重新分配内存并复制元素,性能代价高 ,非必要不使用。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v;
v.reserve(100);  // 容量100
v.push_back(1);  // 大小1,容量100
v.shrink_to_fit();  // 容量缩减至1
cout << v.capacity() << endl;  // 输出:17. max_size():理论最大容量
作用 :返回vector在当前系统中可存储的最大元素数(受系统内存限制,实际很少用到)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v;
cout << v.max_size() << endl;  // 输出一个很大的数(如2^64/4)总结:容量管理核心接口
| 接口 | 作用 | 关键区别 | 
|---|---|---|
| size() | 实际元素个数 | 与"容量"无关 | 
| capacity() | 已分配的最大容纳元素数 | 容量 ≥ 大小 | 
| reserve(n) | 预分配容量(不改变大小) | 仅影响容量,不初始化元素 | 
| resize(n) | 调整大小(可能改变容量) | 会初始化新增元素,可能截断元素 | 
| empty() | 判断是否为空( size() == 0) | 比 size() == 0更简洁 | 
| shrink_to_fit() | 释放多余内存(容量=大小) | 性能代价高,谨慎使用 | 
底层扩容机制(了解)
当vector的大小超过容量时,会自动扩容,通常遵循"翻倍策略":
- 申请一块大小为当前容量2倍(或1.5倍,取决于编译器)的新内存。
- 将旧内存中的元素复制到新内存。
- 释放旧内存,更新容量为新大小。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v;
// 初始容量:0
v.push_back(1);  // 容量变为1
v.push_back(2);  // 容量变为2(1*2)
v.push_back(3);  // 容量变为4(2*2)
v.push_back(4);  // 容量不变(4 ≥ 4)
v.push_back(5);  // 容量变为8(4*2)五、vector的元素修改
vector提供了丰富的接口用于添加、删除、修改元素,以下是最常用的操作:
1. push_back():尾部添加元素
作用 :在vector末尾添加一个元素,若容量不足则自动扩容。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v;
v.push_back(1);
v.push_back(2);
for (int num : v) {
    cout << num << " ";  // 输出:1 2
}
2. pop_back():尾部删除元素
作用 :删除vector的最后一个元素,大小减1(容量不变)。
注意 :不能对空vector使用(否则行为未定义)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
v.pop_back();  // 删除最后一个元素(3)
for (int num : v) {
    cout << num << " ";  // 输出:1 2
}3. insert():指定位置插入元素
语法 :insert(iterator pos, const T& val)
作用 :在迭代器 pos 指向的位置插入元素 val,后续元素依次后移。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
// 在第二个元素(2)前插入10
v.insert(v.begin() + 1, 10);
for (int num : v) {
    cout << num << " ";  // 输出:1 10 2 3
}4. erase():删除指定位置元素
语法 :erase(iterator pos)
作用 :删除迭代器 pos 指向的元素,后续元素依次前移,返回下一个有效迭代器。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
// 删除第二个元素(2)
v.erase(v.begin() + 1);
for (int num : v) {
    cout << num << " ";  // 输出:1 3
}5. swap():交换两个vector
作用 :交换两个vector的内容(元素、大小、容量),效率极高(仅交换指针)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v1 = {1, 2};
vector<int> v2 = {3, 4, 5};
v1.swap(v2);  // 交换v1和v2
for (int num : v1) cout << num << " ";  // 输出:3 4 5
for (int num : v2) cout << num << " ";  // 输出:1 2
6. clear():清空所有元素
作用 :删除vector中的所有元素,大小变为0(容量不变)。
例子:
            
            
              cpp
              
              
            
          
          vector<int> v = {1, 2, 3};
v.clear();
cout << v.size() << endl;     // 输出:0
cout << v.capacity() << endl; // 输出:3(容量不变)
以上就是这篇博客的全部内容,下一篇我们将继续探索STL中vector的高级用法(如迭代器失效问题、与算法库结合等)。
我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343我的C++知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_12880513.html?spm=1001.2014.3001.5482
|--------------------|
| 非常感谢您的阅读,喜欢的话记得三连哦 |
