de风——【从零开始学C++】(九)—vector的基本使用

目录

[📌 前言](#📌 前言)

[一、vector 的构造](#一、vector 的构造)

[1.1 简介作用](#1.1 简介作用)

[1.2 代码示例](#1.2 代码示例)

[示例 1:无参构造(最常用)](#示例 1:无参构造(最常用))

[示例 2:构造 n 个相同值的 vector](#示例 2:构造 n 个相同值的 vector)

[示例 3:拷贝构造](#示例 3:拷贝构造)

[示例 4:迭代器区间构造](#示例 4:迭代器区间构造)

[1.3 ⚠️ 新手经典 Bug](#1.3 ⚠️ 新手经典 Bug)

[二、vector 的迭代器](#二、vector 的迭代器)

[2.1 简介](#2.1 简介)

[2.2 正向迭代](#2.2 正向迭代)

简介作用

代码示例:正向迭代遍历

[2.3 反向迭代](#2.3 反向迭代)

简介作用

代码示例:反向迭代遍历

[2.4 ⚠️ 新手经典 Bug](#2.4 ⚠️ 新手经典 Bug)

[三、vector 的容量接口](#三、vector 的容量接口)

[3.1 简介](#3.1 简介)

[3.2 size - 获取元素个数](#3.2 size - 获取元素个数)

简介作用

代码示例

[3.3 capacity - 获取容量大小](#3.3 capacity - 获取容量大小)

简介作用

代码示例

[3.4 reserve - 预留空间(面试重点)](#3.4 reserve - 预留空间(面试重点))

简介作用

[代码示例:reserve 的使用](#代码示例:reserve 的使用)

[3.5 resize - 改变元素个数](#3.5 resize - 改变元素个数)

简介作用

代码示例

[3.6 🔥 扩容的策略差异(面试必问)](#3.6 🔥 扩容的策略差异(面试必问))

简介作用

代码示例:测试扩容机制

[🎯 优化建议(面试加分项)](#🎯 优化建议(面试加分项))

[3.7 ⚠️ 新手经典 Bug](#3.7 ⚠️ 新手经典 Bug)

[四、vector 的增删查改接口](#四、vector 的增删查改接口)

[4.1 简介作用](#4.1 简介作用)

[4.2 push_back - 尾插](#4.2 push_back - 尾插)

简介作用

代码示例

[4.3 pop_back - 尾删](#4.3 pop_back - 尾删)

简介作用

代码示例

[4.4 insert - 指定位置插入](#4.4 insert - 指定位置插入)

简介作用

代码示例

[4.5 erase - 指定位置删除](#4.5 erase - 指定位置删除)

简介作用

代码示例

[4.6 find - 查找元素(重点!)](#4.6 find - 查找元素(重点!))

简介作用

代码示例

[4.7 swap - 交换两个 vector](#4.7 swap - 交换两个 vector)

简介作用

代码示例

[4.8 operator [] - 下标访问](#4.8 operator [] - 下标访问)

简介作用

代码示例

[4.9 ⚠️ 新手经典 Bug](#4.9 ⚠️ 新手经典 Bug)

[五、🔥 迭代器失效问题(面试必问)](#五、🔥 迭代器失效问题(面试必问))

[5.1 简介作用](#5.1 简介作用)

[5.2 失效场景 1:扩容导致的失效](#5.2 失效场景 1:扩容导致的失效)

问题描述

代码示例:扩容导致迭代器失效

[5.3 失效场景 2:erase 导致的失效](#5.3 失效场景 2:erase 导致的失效)

问题描述

[代码示例:erase 导致迭代器失效](#代码示例:erase 导致迭代器失效)

经典错题:删除所有偶数

[5.4 编译器差异(VS vs g++)](#5.4 编译器差异(VS vs g++))

[5.5 ✅ 解决方法](#5.5 ✅ 解决方法)

[解决方法 1:扩容后重新获取迭代器](#解决方法 1:扩容后重新获取迭代器)

[解决方法 2:利用 erase 的返回值](#解决方法 2:利用 erase 的返回值)

[5.6 ⚠️ 面试答题模板](#5.6 ⚠️ 面试答题模板)

[📝 本篇总结](#📝 本篇总结)

[🎯 下一篇预告](#🎯 下一篇预告)


📌 前言

大家好!我是你们的小小风呀,今天我们继续【从零开始学 C++】专题的第九篇。今天要讲的vector可以说是 STL 容器中最常用、最重要的一个,没有之一!

不管是日常开发还是面试,vector 都是绕不开的重点。尤其是扩容策略差异迭代器失效这两个知识点,更是面试官百考不厌的高频考点!今天我们就从新手视角出发,一步步吃透 vector 的所有核心用法。

💡 学习目标:看完这篇,你不仅能熟练使用 vector 的各种接口,还能从容应对面试中关于 vector 的所有问题!


一、vector 的构造

1.1 简介作用

大白话讲:构造函数就是创建 vector 对象的不同方式。就像买奶茶,你可以买一杯空的(无参),也可以直接买 3 杯珍珠奶茶(n 个相同值),还可以买一杯和别人一模一样的(拷贝构造),甚至可以从别的奶茶店买几杯过来(迭代器区间构造)。

vector 提供了 4 种常用的构造方式,满足不同的创建需求。

1.2 代码示例

示例 1:无参构造(最常用)
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    // 无参构造:创建一个空的vector,里面什么元素都没有
    vector<int> v1;  // 创建空的int类型vector
    
    cout << "v1的大小:" << v1.size() << endl;      // 输出:0
    cout << "v1的容量:" << v1.capacity() << endl;  // 输出:0
    
    return 0;
}
示例 2:构造 n 个相同值的 vector
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    // 构造5个值为10的元素
    vector<int> v2(5, 10);
    
    // 遍历输出
    for (int i = 0; i < v2.size(); i++) {
        cout << v2[i] << " ";  // 输出:10 10 10 10 10
    }
    cout << endl;
    
    return 0;
}
示例 3:拷贝构造
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v1(5, 10);
    
    // 拷贝构造:创建一个和v1一模一样的vector
    vector<int> v2(v1);
    
    for (int i = 0; i < v2.size(); i++) {
        cout << v2[i] << " ";  // 输出:10 10 10 10 10
    }
    cout << endl;
    
    return 0;
}
示例 4:迭代器区间构造
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v1(5, 10);
    
    // 使用迭代器区间构造:取v1的全部元素
    vector<int> v2(v1.begin(), v1.end());
    
    // 也可以用数组来构造
    int arr[] = {1, 2, 3, 4, 5};
    vector<int> v3(arr, arr + 5);  // 数组名就是天然的迭代器
    
    for (int e : v3) {
        cout << e << " ";  // 输出:1 2 3 4 5
    }
    cout << endl;
    
    return 0;
}

1.3 ⚠️ 新手经典 Bug

Bug1:括号误用

cpp 复制代码
// ❌ 错误:这不是创建包含1个元素10的vector,而是声明了一个函数!
vector<int> v();  

// ✅ 正确:无参构造
vector<int> v;

// ✅ 正确:1个元素10
vector<int> v(1, 10);

Bug2:类型不匹配

cpp 复制代码
// ❌ 错误:构造的是int类型vector,却传入string
vector<int> v(5, "hello");

二、vector 的迭代器

2.1 简介

大白话讲:迭代器就是 STL 容器的 "通用遍历工具"。你可以把它理解成一个 "智能指针",指向 vector 中的元素。通过迭代器,我们可以统一方式遍历所有 STL 容器,而不用关心容器底层是什么数据结构。

vector 的迭代器本质就是原生指针,非常好理解!

2.2 正向迭代

简介作用

正向迭代就是从第一个元素走到最后一个元素 ,用begin()获取第一个元素的位置,end()获取最后一个元素的下一个位置(注意不是最后一个元素!)。

代码示例:正向迭代遍历
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v;
    for (int i = 1; i <= 5; i++) {
        v.push_back(i);  // 插入1 2 3 4 5
    }
    
    // 方式1:迭代器正向遍历(标准写法)
    vector<int>::iterator it = v.begin();
    while (it != v.end()) {
        cout << *it << " ";  // 像指针一样解引用
        ++it;  // 移动到下一个元素
    }
    cout << endl;  // 输出:1 2 3 4 5
    
    // 方式2:范围for(底层就是迭代器)
    for (auto e : v) {
        cout << e << " ";  // 输出:1 2 3 4 5
    }
    cout << endl;
    
    return 0;
}

2.3 反向迭代

简介作用

反向迭代就是从最后一个元素走到第一个元素 ,用rbegin()获取最后一个元素的位置,rend()获取第一个元素的前一个位置

代码示例:反向迭代遍历
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v;
    for (int i = 1; i <= 5; i++) {
        v.push_back(i);
    }
    
    // 反向迭代遍历
    vector<int>::reverse_iterator rit = v.rbegin();
    while (rit != v.rend()) {
        cout << *rit << " ";
        ++rit;  // 注意:反向迭代器++也是往前走!
    }
    cout << endl;  // 输出:5 4 3 2 1
    
    return 0;
}

2.4 ⚠️ 新手经典 Bug

Bug1:end () 的理解错误

cpp 复制代码
vector<int> v = {1, 2, 3, 4, 5};
vector<int>::iterator it = v.end();

// ❌ 错误:end()指向的是最后一个元素的下一个位置,不能解引用!
cout << *it << endl;  // 程序崩溃!

Bug2:反向迭代器的方向搞反

cpp 复制代码
// ❌ 错误:反向迭代器应该用rbegin和rend
vector<int>::reverse_iterator rit = v.begin();  // 编译错误!

三、vector 的容量接口

3.1 简介

这部分是面试超级重点!vector 的精髓就在于它的动态扩容机制。这几个接口帮我们管理 vector 的空间:

  • size:当前有多少个元素

  • capacity:总共能存多少个元素(不扩容的前提下)

  • reserve:提前开空间,只改 capacity 不改 size

  • resize:改变元素个数,既改 capacity 也改 size

3.2 size - 获取元素个数

简介作用

size()告诉你 vector 里现在实际装了多少个元素,就像你书包里现在放了几本书。

代码示例
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v;
    cout << "初始size:" << v.size() << endl;  // 输出:0
    
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    
    cout << "插入3个元素后size:" << v.size() << endl;  // 输出:3
    
    v.pop_back();  // 删除最后一个元素
    cout << "删除后size:" << v.size() << endl;  // 输出:2
    
    return 0;
}

3.3 capacity - 获取容量大小

简介作用

capacity()告诉你 vector总共能装多少个元素(不扩容的情况下),就像你书包总共能装几本书。

代码示例
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v;
    for (int i = 0; i < 10; i++) {
        v.push_back(i);
        cout << "size:" << v.size() << " capacity:" << v.capacity() << endl;
    }
    return 0;
}

3.4 reserve - 预留空间(面试重点)

简介作用

reserve(n)就是提前把容量开到 n,避免一边插入一边扩容。这是优化 vector 性能最常用的手段!

代码示例:reserve 的使用
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v;
    
    // 提前预留100个元素的空间
    v.reserve(100);
    
    cout << "reserve后capacity:" << v.capacity() << endl;  // 输出:100
    cout << "reserve后size:" << v.size() << endl;          // 输出:0(注意:size不变!)
    
    // 现在插入100个元素,不会发生扩容!
    for (int i = 0; i < 100; i++) {
        v.push_back(i);
    }
    cout << "插入100个元素后capacity:" << v.capacity() << endl;  // 还是100!
    
    return 0;
}

3.5 resize - 改变元素个数

简介作用

resize(n)把 vector 的元素个数改成 n 个

  • 如果 n > 当前 size:多出的位置用默认值填充

  • 如果 n < 当前 size:删除多余的元素

  • 空间不够时会自动扩容

代码示例
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    
    // 情况1:扩大到8个元素,多出的3个用8填充
    v.resize(8, 8);
    for (auto e : v) {
        cout << e << " ";  // 输出:1 2 3 4 5 8 8 8
    }
    cout << endl;
    
    // 情况2:缩小到3个元素
    v.resize(3);
    for (auto e : v) {
        cout << e << " ";  // 输出:1 2 3
    }
    cout << endl;
    
    return 0;
}

3.6 🔥 扩容的策略差异(面试必问)

简介作用

这是面试 100% 会考 的知识点!vector 不是来一个元素开一个空间,那样效率太低了。它会一次性多开一些空间,这就是扩容策略。

重点来了:不同编译器扩容倍数不一样!

  • VS(PJ 版 STL):按 1.5 倍扩容

  • g++(SGI 版 STL):按 2 倍扩容

代码示例:测试扩容机制
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

// 测试vector的默认扩容机制
void TestVectorExpand() {
    size_t sz;
    vector<int> v;
    sz = v.capacity();
    cout << "开始测试扩容:" << endl;
    
    for (int i = 0; i < 100; ++i) {
        v.push_back(i);
        if (sz != v.capacity()) {
            sz = v.capacity();
            cout << "capacity变为:" << sz << endl;
        }
    }
}

int main() {
    TestVectorExpand();
    return 0;
}

VS 下运行结果(1.5 倍扩容):

cpp 复制代码
capacity变为:1
capacity变为:2
capacity变为:3
capacity变为:4
capacity变为:6
capacity变为:9
capacity变为:13
capacity变为:19
capacity变为:28
capacity变为:42
capacity变为:63
capacity变为:94
capacity变为:141

g++ 下运行结果(2 倍扩容):

cpp 复制代码
capacity变为:1
capacity变为:2
capacity变为:4
capacity变为:8
capacity变为:16
capacity变为:32
capacity变为:64
capacity变为:128
🎯 优化建议(面试加分项)
  1. 提前用 reserve 预留空间:如果知道大概要存多少元素,一定要提前 reserve!避免多次扩容(扩容需要:重新配置空间 + 拷贝元素 + 释放旧空间,非常耗时)

  2. 不要频繁小量插入:批量插入比一个个插入效率高很多

  3. 1.5 倍 vs 2 倍的优劣

    1. 2 倍扩容:扩容次数少,但空间浪费可能更多

    2. 1.5 倍扩容:空间利用率更高,但扩容次数多一些

3.7 ⚠️ 新手经典 Bug

Bug1:reserve 和 resize 搞混

cpp 复制代码
vector<int> v;
v.reserve(10);  // 只开空间,不创建元素

// ❌ 错误:reserve后size还是0,不能用[]访问!
v[0] = 10;  // 越界访问!程序崩溃

Bug2:resize 的默认值问题

cpp 复制代码
vector<int> v = {1, 2, 3};
v.resize(5);  // 不指定填充值,默认用0填充
// 结果:1 2 3 0 0

四、vector 的增删查改接口

4.1 简介作用

这部分就是 vector 的日常操作,就像数组的增删查改,但比数组功能强大多了!这些接口 90% 的开发场景都会用到,必须熟练掌握。

4.2 push_back - 尾插

简介作用

在 vector 的最后面插入一个元素,这是最常用的插入方式,效率最高。

代码示例
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v;
    
    // 尾插元素
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    
    for (auto e : v) {
        cout << e << " ";  // 输出:1 2 3
    }
    cout << endl;
    
    return 0;
}

4.3 pop_back - 尾删

简介作用

删除 vector 的最后一个元素,也是效率最高的删除方式。

代码示例
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    
    v.pop_back();  // 删除最后一个元素5
    v.pop_back();  // 删除最后一个元素4
    
    for (auto e : v) {
        cout << e << " ";  // 输出:1 2 3
    }
    cout << endl;
    
    return 0;
}

4.4 insert - 指定位置插入

简介作用

指定位置之前插入元素。注意:insert 效率比 push_back 低,因为要移动元素。

代码示例
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4};
    
    // 在第2个位置(值为2的前面)插入10
    v.insert(v.begin() + 1, 10);
    
    for (auto e : v) {
        cout << e << " ";  // 输出:1 10 2 3 4
    }
    cout << endl;
    
    // 插入n个相同元素
    v.insert(v.begin(), 3, 0);  // 在开头插入3个0
    for (auto e : v) {
        cout << e << " ";  // 输出:0 0 0 1 10 2 3 4
    }
    cout << endl;
    
    return 0;
}

4.5 erase - 指定位置删除

简介作用

删除指定位置的元素,或者删除一个区间的元素。

代码示例
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    
    // 删除第3个元素(值为3)
    v.erase(v.begin() + 2);
    
    for (auto e : v) {
        cout << e << " ";  // 输出:1 2 4 5
    }
    cout << endl;
    
    // 删除区间:删除第2个到最后
    v.erase(v.begin() + 1, v.end());
    for (auto e : v) {
        cout << e << " ";  // 输出:1
    }
    cout << endl;
    
    return 0;
}

4.6 find - 查找元素(重点!)

简介作用

划重点:find 不是 vector 的成员函数! 它是算法库 里的函数,在<algorithm>头文件中。所有 STL 容器都可以用这个 find 来查找元素。

代码示例
cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>  // 必须包含这个头文件!
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    
    // 查找元素3
    // 参数:查找区间[begin, end),要找的值
    vector<int>::iterator pos = find(v.begin(), v.end(), 3);
    
    if (pos != v.end()) {
        cout << "找到了,值为:" << *pos << endl;  // 输出:找到了,值为:3
    } else {
        cout << "没找到" << endl;
    }
    
    // 找到后配合erase删除
    pos = find(v.begin(), v.end(), 3);
    if (pos != v.end()) {
        v.erase(pos);  // 删除找到的元素
    }
    
    for (auto e : v) {
        cout << e << " ";  // 输出:1 2 4 5
    }
    cout << endl;
    
    return 0;
}

4.7 swap - 交换两个 vector

简介作用

交换两个 vector 的数据空间,注意:不是逐个元素交换,是直接交换内部指针,效率极高!

代码示例
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v1 = {1, 2, 3};
    vector<int> v2 = {10, 20, 30, 40};
    
    cout << "交换前:" << endl;
    cout << "v1 size: " << v1.size() << endl;  // 3
    cout << "v2 size: " << v2.size() << endl;  // 4
    
    v1.swap(v2);  // 交换
    
    cout << "交换后:" << endl;
    cout << "v1 size: " << v1.size() << endl;  // 4
    cout << "v2 size: " << v2.size() << endl;  // 3
    
    return 0;
}

4.8 operator [] - 下标访问

简介作用

像数组一样用[]访问元素,这是 vector 最方便的地方,也是我们最常用的访问方式。

代码示例
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    
    // 读操作
    cout << v[0] << endl;  // 输出:1
    cout << v[2] << endl;  // 输出:3
    
    // 写操作
    v[0] = 100;
    v[1] = 200;
    
    for (int i = 0; i < v.size(); i++) {
        cout << v[i] << " ";  // 输出:100 200 3 4 5
    }
    cout << endl;
    
    return 0;
}

4.9 ⚠️ 新手经典 Bug

Bug1:find 忘记包含头文件

cpp 复制代码
// ❌ 错误:必须包含<algorithm>!
#include <vector>
find(v.begin(), v.end(), 3);  // 编译错误!

Bug2:下标越界

cpp 复制代码
vector<int> v = {1, 2, 3};
// ❌ 错误:越界访问,行为未定义!
cout << v[10] << endl;  // 可能崩溃,可能输出乱码

Bug3:insert/erase 的位置参数

cpp 复制代码
vector<int> v = {1, 2, 3};
// ❌ 错误:参数必须是迭代器,不能是整数!
v.insert(1, 10);  // 编译错误!

// ✅ 正确
v.insert(v.begin() + 1, 10);

五、🔥 迭代器失效问题(面试必问)

5.1 简介作用

这是 vector最难、最容易出错、面试最常考的知识点!

迭代器失效大白话讲:你手里的 "指针"(迭代器)指向的空间已经不是原来的空间了,或者那个位置已经没有元素了,再用这个迭代器就会出问题。

记住:凡是会引起底层空间变化或元素位置变化的操作,都可能导致迭代器失效!

5.2 失效场景 1:扩容导致的失效

问题描述

当 vector 发生扩容时(push_back、insert、reserve、resize 等),会释放旧空间,开辟新空间,原来的迭代器都指向已经释放的旧空间,全部失效!

代码示例:扩容导致迭代器失效
cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    auto it = v.begin();
    
    cout << "扩容前capacity:" << v.capacity() << endl;
    
    // 触发扩容:reserve到100
    v.reserve(100);
    
    cout << "扩容后capacity:" << v.capacity() << endl;
    
    // ❌ 危险!it已经失效了,指向的是已经释放的旧空间!
    // VS下直接崩溃,g++下可能运行但结果错误
    while (it != v.end()) {
        cout << *it << " ";  // 非法访问!
        ++it;
    }
    cout << endl;
    
    return 0;
}

5.3 失效场景 2:erase 导致的失效

问题描述

erase 删除元素后,后面的元素会往前移动。虽然空间没变,但元素位置变了,被删除位置及之后的迭代器都失效了。

代码示例:erase 导致迭代器失效
cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    
    // 找到元素3的位置
    auto pos = find(v.begin(), v.end(), 3);
    
    v.erase(pos);  // 删除pos位置的元素
    
    // ❌ 危险!pos已经失效了!
    cout << *pos << endl;  // VS下直接崩溃!
    
    return 0;
}
经典错题:删除所有偶数
cpp 复制代码
// ❌ 错误写法!100%面试会考找错题
int main() {
    vector<int> v = {1, 2, 3, 4};
    auto it = v.begin();
    while (it != v.end()) {
        if (*it % 2 == 0) {
            v.erase(it);  // erase后it已经失效了!
        }
        ++it;  // 对失效的迭代器++,崩溃!
    }
    return 0;
}

5.4 编译器差异(VS vs g++)

这也是面试常考点!不同编译器对迭代器失效的检查严格程度不一样:

|---------------|----------|----------------|
| 场景 | VS(检查严格) | g++(检查宽松) |
| 扩容后使用旧迭代器 | 直接崩溃 | 可能运行,但结果错误 |
| erase 任意位置后使用 | 直接崩溃 | 非尾删可能正常运行,尾删崩溃 |

结论:VS 是 "好学生",严格按标准来;g++ 是 "老好人",能跑就不报错,但不代表代码是对的!

5.5 ✅ 解决方法

核心原则:每次使用前,重新给迭代器赋值!

解决方法 1:扩容后重新获取迭代器
cpp 复制代码
int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    
    v.reserve(100);  // 扩容
    
    // ✅ 正确:扩容后重新获取begin()
    auto it = v.begin();
    while (it != v.end()) {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
    
    return 0;
}
解决方法 2:利用 erase 的返回值

erase 会返回被删除元素的下一个位置的有效迭代器

cpp 复制代码
// ✅ 正确写法:删除所有偶数
int main() {
    vector<int> v = {1, 2, 3, 4};
    auto it = v.begin();
    while (it != v.end()) {
        if (*it % 2 == 0) {
            it = v.erase(it);  // 用返回值更新it!
        } else {
            ++it;  // 不删除才++
        }
    }
    
    for (auto e : v) {
        cout << e << " ";  // 输出:1 3
    }
    cout << endl;
    
    return 0;
}

5.6 ⚠️ 面试答题模板

面试官问:"说说 vector 迭代器失效的情况?"

你这样答:

迭代器失效分两种情况:

  1. 扩容导致:push_back、insert、reserve、resize 等操作可能触发扩容,释放旧空间,所有迭代器都失效

  2. erase 导致:删除元素后,被删位置及之后的迭代器失效

编译器差异:VS 检查严格,直接崩溃;g++ 较宽松,但不代表正确

解决方法:每次操作后重新获取迭代器,或利用 erase 的返回值更新迭代器


📝 本篇总结

今天我们把 vector 的核心用法全部过了一遍,划重点:

  1. 4 种构造方式:无参、n 个 val、拷贝、迭代器区间

  2. 2 种迭代器:正向(begin/end)、反向(rbegin/rend)

  3. 4 个容量接口:size、capacity、reserve、resize

  4. ⭐扩容策略:VS 1.5 倍,g++ 2 倍,提前 reserve 优化

  5. 7 个增删查改接口:push_back、pop_back、insert、erase、find(算法库)、swap、operator []

  6. ⭐迭代器失效:扩容 + erase 两种场景,用返回值更新迭代器

💡 面试重点:扩容策略差异、迭代器失效场景及解决方法,这两个一定要背下来!


🎯 下一篇预告

下一篇我们将进入 vector 的底层模拟实现,亲手写一个 vector,深入理解它的底层原理,这也是面试手写代码的高频题!

觉得有帮助的话,点赞收藏关注不迷路,我们下一篇见!🚀


【从零开始学 C++】专题系列:

  • 第一篇:C++ 入门基础

  • 第二篇:类和对象(上)

  • 第三篇:类和对象(中)

  • 第四篇:类和对象(下)

  • 第五篇:C++ 内存管理

  • 第六篇:string 类的使用

  • 第七篇:string 类的模拟实现

  • 第八篇:STL 简介

  • 第九篇:vector 的基本使用 ←你在这里哦!

  • 第十篇:vector 的模拟实现

相关推荐
threelab3 小时前
Three.js 加载 3D Tiles 瓦片数据 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器
_洋3 小时前
Three.js加载 .obj文件 和 .gltf文件
开发语言·javascript·ecmascript
wjs20243 小时前
Font Awesome 性别图标
开发语言
SmartBrain3 小时前
AI全栈开发(SDD):慢病管理系统工程级设计
java·大数据·开发语言·人工智能·架构·aigc
lsx2024064 小时前
选择(Selectable)
开发语言
漠效4 小时前
随机代理‌IP访问脚本
开发语言·python
SilentSamsara4 小时前
元类与 __init_subclass__:类是如何被“创建“出来的
开发语言·python·青少年编程
小a杰.4 小时前
Ascend C算子开发实战 - 从零开始写算子
c语言·开发语言
雪度娃娃4 小时前
Asio异步读写——连接的安全回收问题
开发语言·c++·安全·php
baivfhpwxf20234 小时前
c# 中对像之间频繁的转换会慢吗?
开发语言·c#