std::remove 并不真正删除元素,而是将匹配元素移至容器末尾并返回新逻辑结尾迭代器,需配合 erase 才能真正移除;它不改变 size、不调用析构函数、要求 operator== 支持值比较,且必须与 erase 联用构成 erase-remove 惯用法。

std::remove 不是真的删除元素
std::remove 只是把要移除的值“挤到”容器末尾,并返回一个指向新逻辑结尾的迭代器,原容器大小不变。它不改变容器 size,也不调用任何元素的析构函数——这是最常被误解的一点。
常见错误现象:vec.size() 没变,打印出来发现“被删”的值还在末尾;或者误以为 std::remove 能直接用于 std::list(其实可以,但效率不如 list::remove)。
- 必须配合容器的
erase方法才能真正删掉:即 “erase–remove 惯用法” - 只适用于支持随机访问迭代器的容器(
std::vector、std::array、std::string),对std::list或std::forward_list推荐用自带的remove成员函数 - 时间复杂度是 O(n),但不会触发多次移动——它用单次遍历重排元素
正确写法:erase-remove 惯用法
对 std::vector,必须链式调用 erase 和 remove:
std::vector<int> vec = {1, 2, 3, 2, 4, 2};
vec.erase(std::remove(vec.begin(), vec.end(), 2), vec.end());
// 现在 vec 是 {1, 3, 4}
</int>
说明:std::remove 返回的是“新有效范围”的尾后迭代器,erase 删除从该位置到原 end() 的所有元素。
- 不能只写
std::remove(vec.begin(), vec.end(), 2)—— 这什么都没删 - 不能反着写:
vec.erase(vec.begin(), std::remove(...))—— 会删错区间 - 如果容器为空,
std::remove返回begin(),erase(begin(), begin())是安全的
移除自定义类型时要注意 operator==
std::remove 内部用 operator== 判断相等,所以你的类必须定义可访问的 == 运算符,否则编译失败。
示例:
struct Person {
std::string name;
int age;
bool operator==(const Person& other) const {
return name == other.name && age == other.age;
}
};
std::vector<person> people = {{"Alice", 30}, {"Bob", 25}, {"Alice", 30}};
people.erase(std::remove(people.begin(), people.end(), {"Alice", 30}), people.end());
</person>
- 如果
operator==没声明为const,或参数不是const&,可能匹配失败 - 注意值语义:传入的比较对象是临时值,确保它能和容器中元素正确比对
- 对于指针或智能指针容器,
std::remove比较的是指针值本身,不是所指对象
替代方案:std::remove_if 更灵活
当移除条件不是简单值相等(比如大于某阈值、满足正则、成员字段匹配),用 std::remove_if 更合适。
例如移除所有偶数:
vec.erase(std::remove_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; }), vec.end());
-
std::remove_if第三个参数是可调用对象(lambda、函数指针、functor) - 和
std::remove一样,必须配erase才生效 - 性能上无本质差异,但逻辑更清晰——避免为了用
std::remove而构造假的“目标值”
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











