应使用std::erase(c++20)或std::remove_if+erase组合删除vector中空字符串,避免迭代器失效;前者仅支持值相等删除,后者通过谓词灵活判断“空”,且兼容c++11起所有标准。

vector里删空字符串,别直接用erase遍历删
直接写for (auto it = v.begin(); it != v.end(); ++it)再if (*it.empty()) v.erase(it)会崩——迭代器失效后++it行为未定义。C++11起标准推荐用std::erase(C++20)或std::remove_if+erase组合(C++11~C++17),本质是“搬数据+截断”,安全且高效。
std::erase(C++20):一行解决,但注意编译器支持
如果你的项目已启用C++20且编译器支持(GCC 11+、Clang 14+、MSVC 19.30+),直接调用容器专属std::erase最简洁:
std::vector<:string> v = {"a", "", "b", "", ""};
std::erase(v, ""); // 删除所有等于""的元素
</:string>
它内部做了remove_if+erase封装,但只适用于值相等判断。不支持谓词(比如删掉长度为0的字符串,而不管内容是不是"")。
- 只删完全匹配的值,不能传lambda
- 对
std::vector、std::deque、std::list等有重载,但std::array不支持 - 若用旧标准编译,会报错:
'erase' is not a member of 'std'
std::remove_if + erase:C++11起通用解法
这是最稳妥、兼容性最好的方式,核心是“逻辑删除+物理截断”两步:
v.erase(std::remove_if(v.begin(), v.end(), [](const std::string& s) { return s.empty(); }), v.end());
std::remove_if不真删,而是把满足条件的元素挪到末尾,返回新逻辑终点;erase再从该点删到v.end()。关键点:
- 必须成对使用,漏掉
erase只会“看起来没删”,实际末尾残留脏数据 - lambda捕获要谨慎:如果删的是指针或自定义对象,确保判空逻辑正确(比如
ptr == nullptrvsptr && ptr->empty()) - 对
std::vector<:string></:string>,s.empty()比s == ""更高效(避免构造临时std::string) - 若vector很大,这仍是O(n)时间、O(1)空间,但会触发多次移动赋值——对非平凡类型(如含资源的类)要注意移动语义是否已正确定义
删“空”的定义不同,写法就得变
“空”不等于"":可能是nullptr(std::vector<const char></const>)、std::nullopt(std::vector<:optional>></:optional>)、或自定义is_empty()方法。这时候只能靠remove_if+谓词:
// 删掉所有为 nullptr 的 char* 元素
v.erase(std::remove_if(v.begin(), v.end(), [](const char* p) { return p == nullptr; }), v.end());
<p>// 删掉所有没有值的 optional
std::vector<:optional>> opt_v = {{1}, {}, {2}, {}};
opt_v.erase(std::remove_if(opt_v.begin(), opt_v.end(), [](const auto& o) { return !o.has_value(); }), opt_v.end());
</:optional></p>
注意std::optional::has_value()不能简写成!o——虽然可行,但可读性差,且对某些类型(如optional<bool></bool>)易歧义。
真正容易被忽略的是:如果vector里存的是自定义类,且该类empty()是const成员函数,lambda参数务必声明为const T&,否则编译失败;若忘了加const,错误信息往往指向remove_if内部,而不是你的lambda。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











