在 C++ 中,当 vector 容器里的某些数据不再需要时,我们可以随时将它们从容器中移除。根据删除需求的不同,常用的有以下 4 种方式:
- pop_back():删除容器末尾的最后一个元素,执行速度最快。
- erase():按指定位置删除单个元素,或删除一段连续区间的元素。
- std::erase():C++20 新增,直接按元素的值删除所有匹配项。
- clear():一次性清空容器中的所有元素。
删除末尾元素:pop_back()
如果我们只想删掉排在最后面的那个元素,直接调用 pop_back() 成员函数就可以了。其中 pop_back 是 “从末尾弹出” 的意思,刚好与上一节学习的 push_back() 相反。由于删除末尾元素不需要搬移前面的数据,它的执行效率是最高的。
语法:
容器名.pop_back();说明:
pop_back() 的小括号内不需要传入任何参数。每调用一次 pop_back(),函数就会移除容器末尾的最后一个元素,同时元素数量 size() 会自动减 1。
示例 1:删除末尾元素
#include <iostream>
#include <vector>
int main() {
std::vector<int> scores = {75, 88, 96};
scores.pop_back(); // 删除末尾元素 96
std::cout << "剩余元素数量:" << scores.size() << '\n';
std::cout << scores[0] << ' ' << scores[1] << '\n';
return 0;
}运行结果如下。
剩余元素数量:2
75 88分析:
scores.pop_back(); 会把排在最后的 96 移除,容器中只剩下 75 和 88,因此 scores.size() 变成了 2。下面这段代码中,连续执行增删操作后,nums.back() 最终的值是 20,小伙伴们可以思考一下为什么。
std::vector<int> nums = {10, 20, 30};
nums.pop_back();
nums.push_back(40);
nums.pop_back();需要注意的是,pop_back() 的返回值类型是 void。它只负责移除末尾元素,并不会把删掉的值返回出来。如果我们既想拿到最后一个元素的值,又想把它删掉,应该先调用 back() 读取,再调用 pop_back() 移除。
std::vector<int> scores = {75, 88, 96};
// 正确方式
int last = scores.back();
scores.pop_back();
// 错误方式
int last = scores.pop_back();此外,调用 pop_back() 前要确保容器不为空。如果对空容器调用 pop_back() 会引发越界错误,不确定时我们可以先通过 !scores.empty() 做一次判断。
按位置删除元素:erase()
如果要删除的不是最后一个元素,而是开头或中间某个位置的元素,我们就需要使用 erase() 成员函数。
与 insert() 一样,erase() 的参数也不能直接写整数下标,而是通过 容器名.begin() + 下标 来指定位置。它主要有两种常用写法:一种是 “删除单个元素”,另一种是 “删除一段区间的元素”。
1. 删除单个元素
只传入一个位置参数时,erase() 会把该位置上的元素删掉。
语法:
容器名.erase(容器名.begin() + 下标);说明:
删除指定位置的元素后,排在它后面的所有元素都会自动往前移动一位来补齐空缺,同时容器的 size() 减 1。如果要删除第 1 个元素(下标 0),直接写成 容器名.erase(容器名.begin()) 即可。
示例 2:删除单个元素
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {10, 20, 30, 40};
nums.erase(nums.begin() + 1); // 删除下标 1 处的 20
std::cout << "剩余元素数量:" << nums.size() << '\n';
for (int num : nums) {
std::cout << num << ' ';
}
std::cout << '\n';
return 0;
}运行结果如下。
剩余元素数量:3
10 30 40分析:
在这个例子中,nums.erase(nums.begin() + 1); 表示删除下标为 1 的元素 20。把 20 删掉后,后面的 30 和 40 会自动往前顺移一位,随后我们配合范围 for 循环把剩余的 3 个元素打印出来。
这里小伙伴们要留意一个细节:元素往前顺移之后,它们的下标也会跟着变小。比如上面删掉下标 1 的 20 之后,原本排在下标 2 的 30,新的下标就变成了 1。如果需要连续按位置删除多个元素,一定要按删除后的新下标来计算位置。
另外顺便提一点:vector 并没有提供名为 pop_front() 的成员函数,平时想要删除开头的第 1 个元素,使用的就是 nums.erase(nums.begin())。
2. 删除一段区间的元素
除了删除单个元素,erase() 还支持传入起始位置和结束位置,一次性删掉连续的多个元素。
语法:
容器名.erase(容器名.begin() + m, 容器名.begin() + n);说明:
其中,m 是起始下标,n 是结束下标。这里的区间遵循 “包头不包尾(左闭右开)” 的规则:包含起始下标 m 的元素,但不包含结束下标 n 本身。
比如传入 begin() + 1 和 begin() + 4,实际删掉的是下标 1、2、3 这 3 个位置的元素,下标 4 的元素会保留下来。如果希望从下标 m 开始一直删到容器末尾,第 2 个参数可以直接写成 容器名.end()。
示例 3:删除指定区间的元素
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {10, 20, 30, 40, 50};
// 删除下标 1 到 3 的元素
nums.erase(nums.begin() + 1, nums.begin() + 4);
std::cout << "剩余元素数量:" << nums.size() << '\n';
std::cout << nums[0] << ' ' << nums[1] << '\n';
return 0;
}运行结果如下。
剩余元素数量:2
10 50分析:
按照 “包含起点 1、不包含终点 4” 的规则,上面代码实际删掉了下标 1、2、3 处的 20、30、40,而下标 4 处的 50 会保留下来并往前补齐到下标 1 的位置。
平时我们也可以通过简单的减法来快速核对删除个数:终点下标 4 减去起点下标 1 等于 3,说明一共删掉了 3 个元素。
按值删除元素:std::erase()
前面介绍的 容器名.erase() 是根据 “位置” 来删除元素的。但在实际开发中,我们有时并不清楚目标元素排在第几个位置,只想把容器中所有等于某个值的元素全部删掉。
从 C++20 标准开始,<vector> 头文件提供了一个通用函数 std::erase(),可以直接按元素的值删除数据。
语法:
std::erase(容器名, 目标值);说明:
这里要注意调用写法上的区别:按位置删除写的是成员函数 容器名.erase(...),而按值删除写的是带 std:: 前缀的独立函数 std::erase(容器名, 目标值)。
std::erase() 会从头到尾扫描整个容器,把所有等于 “目标值” 的元素全部移除,并返回本次删除的元素个数。如果容器中不存在该目标值,函数不会报错,而是直接返回 0。
示例 4:按值删除所有匹配元素
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {10, 20, 30, 20, 40};
auto count = std::erase(nums, 20); // 删除所有的 20
std::cout << "删除个数:" << count << '\n';
for (int num : nums) {
std::cout << num << ' ';
}
std::cout << '\n';
return 0;
}运行结果如下。
删除个数:2
10 30 40分析:
在这个例子中,我们调用 std::erase(nums, 20) 把 nums 里的两个 20 全部移除,剩下的 10、30、40 会自动往前靠拢对齐。同时,我们配合 auto 关键字定义变量 count 接收返回值,得到本次删除的元素个数为 2。
如果平时不需要统计删除了多少个元素,我们也可以不接收返回值,直接写一句 std::erase(nums, 20); 即可。
清空所有元素:clear()
如果我们需要一次性把 vector 里的所有元素全部删光,让它重新变回空容器,可以使用 clear() 成员函数。
语法:
容器名.clear();说明:
调用 clear() 会一次性移除容器中的所有元素。执行后,size() 会变成 0,empty() 也会返回 true。
示例 5:清空所有元素
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {10, 20, 30};
std::cout << "清空前数量:" << nums.size() << '\n';
nums.clear(); // 清空所有元素
std::cout << "清空后数量:" << nums.size() << '\n';
return 0;
}运行结果如下。
清空前数量:3
清空后数量:0分析:
nums.clear(); 把容器里的 3 个元素一次性全部清空,因此 nums.size() 的结果从 3 变成了 0。清空之后的 nums 依然可以继续正常使用,我们随时能够调用 push_back() 重新往里面添加新元素。
提示 调用 clear() 只会把实际元素数量 size() 清零,通常不会立即释放 vector 在底层已经申请好的内存容量。关于元素数量与底层容量的关系,后面在 “C++ vector size 与 capacity” 一节中还会详细介绍。
