无效的迭代器:在不降低效率的情况下使用 UB 修复函数

问题描述

考虑以下函数

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();
  }
}