问题描述
考虑以下函数:
template<class T>
void remove_unordered(std::vector<T>& vec,T const& val)
{
auto it = begin(vec);
while (it != end(vec)) {
if (*it == val) {
*it = std::move(vec.back());
vec.pop_back();
}
else { ++it; }
}
}
问题是当 it
指向最后一个元素并且该元素被删除时。这使迭代器无效,因此这是 UB。它应该正常工作,因为迭代器实际上是结束。
Can you pop_back a vector and still use the iterator to the last element? 基本上问了同样的问题。答案并没有以效率低得多的方式修复该功能。所以我还在想有没有更好的方法可以不用UB。
解决方法
以下应该是一种可能的解决方法,尽管它看起来不太好并且几乎没有额外的工作:
template<class T>
void remove_unordered(std::vector<T>& vec,T const& val)
{
if(vec.empty()) { return; }
auto it = begin(vec);
while (it+1 != end(vec)) {
if (*it == val) {
*it = std::move(vec.back());
vec.pop_back();
}
else { ++it; }
}
if (*it == val) {
vec.pop_back();
}
}