2.12、remove 和 erase 区别
1. rem)ove和erase的本质区别
remove
- • 作用:重新排列容器中的元素,将不需要删除的元素移动到序列前部,返回指向“新末尾”的迭代器。
- • 关键特性:
- • 不真正删除容器中的元素,也不改变容器大小。
- • 仅将要删除的元素“覆盖”或“移动”到序列后面,容器尾部元素变为未定义状态。
- • 依赖性:和容器类型无关,只依赖于迭代器。
erase(成员函数)
- • 定义:是容器(如
std::vector
、std::list
等)提供的成员函数。 - • 作用:真正从容器中删除元素,改变容器大小,并释放相应内存(对于动态数组容器如
vector
)。 - • 参数:接受一个或一对迭代器,删除指定位置或范围内的元素。
- • 依赖性:需要容器自身实现,删除元素后容器需调整内部结构(如移动元素、更新大小等)。
2. 为什么需要“erase-remove惯用法”?
- • 原因:
remove
不改变容器大小,仅将不需要的元素移动到后面,容器尾部仍保留“垃圾”元素,需调用容器的erase
真正删除这些元素。 - • 典型用法:
auto new_end = std::remove(vec.begin(), vec.end(), value_to_remove); vec.erase(new_end, vec.end());
- •
remove
将所有不等于value_to_remove
的元素移动到前面,返回新的逻辑末尾迭代器new_end
。 - •
erase
负责真正删除从new_end
到vec.end()
之间的元素,缩小容器大小。
- •
3. 详细示例说明
std::vector<int> vec = {1, 2, 3, 4, 5, 3, 6};
// 只调用 remove
auto new_end = std::remove(vec.begin(), vec.end(), 3);
// vec 现在看起来像 {1, 2, 4, 5, 6, ?, ?},但 size 仍是7
std::cout << "Size after remove: " << vec.size() << std::endl; // 输出7
// 需要调用 erase 真正删除
vec.erase(new_end, vec.end());
std::cout << "Size after erase: " << vec.size() << std::endl; // 输出5
4.设计理念与性能考量
- • 设计理念:
- •
std::remove
是通用算法,不依赖容器实现,负责“逻辑删除”(移动元素)。 - •
erase
是容器成员函数,负责物理删除和内存管理。
- •
- • 性能:
- • 若只用
erase
多次删除元素,每次删除后都需移动后续元素,性能开销大。 - •
remove
一次遍历完成元素移动,erase
一次调用完成删除,整体效率更高。
- • 若只用
5. C++20引入的std::erase和std::erase_if
- • 作用:封装了“erase-remove惯用法”,使代码更简洁。
- • 示例:
std::vector<int> vec = {1, 2, 3, 4, 5}; std::erase(vec, 3); // 直接删除所有值为3的元素
6. 总结
方面 | std::remove | erase(容器成员函数) |
类型 | 算法(algorithm) | 容器成员函数 |
功能 | 重新排列元素,移动不删除的元素到前面 | 真正删除元素,改变容器大小 |
是否改变大小 | 不改变容器大小 | 改变容器大小 |
是否释放内存 | 不释放内存 | 释放内存 |
依赖 | 仅依赖迭代器 | 依赖容器内部实现 |
典型用法 | 与erase 配合使用,形成“erase-remove惯用法” |
单独调用删除指定位置或范围元素 |
性能 | 一次遍历移动元素,避免多次移动开销 | 多次调用可能导致多次元素移动,效率较低 |
本文首发于【讳疾忌医-note】公众号,未经授权,不得转载。
(加入我的知识星球,免费获取账号,解锁所有文章。)
阅读剩余
版权声明:
作者:讳疾忌医-note
链接:https://www.1217zy.vip/archives/1841
文章版权归作者所有,未经允许请勿转载。
THE END