从C++ std::vector中删除元素

7
什么是在遍历C++向量时删除元素的正确方法?我正在遍历一个数组,并希望删除一些符合特定条件的元素。我被告知在遍历期间修改它是一件坏事。
我想我还应该提到这是一个指针数组,我需要在删除它们之前释放它们。
编辑:
下面是我的代码片段。

void RoutingProtocolImpl::removeAllInfinity()
{
  dv.erase(std::remove_if(dv.begin(), dv.end(), hasInfCost), dv.end()); 
}

bool RoutingProtocolImpl::hasInfCost(RoutingProtocolImpl::dv_entry *entry)
{
  if (entry->link_cost == INFINITY_COST)
  {
    free(entry);
    return true;
  }
  else
  {
    return false;
  }
}

I'm getting the following error when compiling:


RoutingProtocolImpl.cc:368: error: argument of type <code>bool (RoutingProtocolImpl::)(RoutingProtocolImpl::dv_entry*)' does not match</code>bool (RoutingProtocolImpl::<em>)(RoutingProtocolImpl::dv_entry</em>)'

抱歉,我有点 C++ 初学者。


不应该使用delete而不是free吗?free是C机制,不应与目标代码混淆。 - Matthieu M.
此外,如果您有一个 vector<T*> 并且该向量拥有这些对象,请考虑改用 boost::ptr_vector<T>,这样您就可以确保不会泄漏。该接口与 vector<T> 非常相似,只是在幕后提供指针和所有权处理。 - Matthieu M.
@garsh0p:你之前的问题(https://dev59.com/703Sa4cB1Zd3GeqPtDCX)和这个问题几乎一模一样(看起来是复制粘贴的)。请不要这样做。如果你想在问题中添加更多细节,请编辑现有的问题,或者只需在问题下面添加评论即可。 - Evan Teran
@Evan Teran:Brian R. Bondy 在下面告诉我要创建一个新问题... - meteoritepanama
3个回答

24

向量(vector)的erase()方法返回一个新的迭代器,可用于继续迭代:

std::vecor<MyClass> v = ...;
std::vecor<MyClass>::iterator it = v.begin();
while (it != v.end()) {
  if (some_condition(*it)) {
    it->cleanup(); // or something
    it = v.erase(it);
  }
  else {
    ++it;
  }
}

2
+1 是为了实际回答问题,而不是描述完全不同的方法。问题明确指出“在迭代过程中”。 - kibibu
1
注意:一定要记得将 it 赋值为 erase 返回的迭代器!很容易忘记,而且代码看起来仍然没问题,但会出现严重错误。 - kibibu
2
出于与kibibu相同的原因,但是应该优先选择算法调用而不是显式循环。 - Billy ONeal

15
bool IsEven (int i) 
{ 
  return (i%2) == 0; 
}

//...

std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.erase(std::remove_if(v.begin(),v.end(),IsEven), v.end()); 
//v now contains 1 and 3

如果我的向量是指针,需要在移除后释放它们,我该怎么做? - meteoritepanama
1
@user219847 你可以使用Boost:smart_ptr对象来包装你的指针。 - wheaties
在这个例子中,谓词IsEven可以处理指向的内存释放...这取决于您正在开发的应用程序最合适的方式...我倾向于使用for_each,因为它更易读 - 对我来说。 - Jason D
@Brian R. Bondy:我遇到了一些编译错误的问题。我已经编辑了我的问题。 - meteoritepanama
请将其作为一个新问题发布,我认为这与它是成员函数有关。 - Brian R. Bondy
显示剩余3条评论

5
与Brian R. Bondy的答案相同,但我会使用functor而不是函数指针,因为编译器更擅长内联它们。
struct IsEven : public std::unary_function<int, bool>
{
    bool operator()(int i) 
    { 
      return (i%2) == 0; 
    };
}

//...

std::erase(std::remove_if(v.begin(),v.end(),IsEven()), v.end());

编辑:针对如果我的向量是指针,需要在删除后释放它们,我该怎么做?

struct IsEven : public std::unary_function<int, bool>
{
    bool operator()(int i) 
    { 
      return (i%2) == 0; 
    };
}

struct DeletePointer : public std::unary_function<myPointedType *, void>
{
    void operator()(myPointedType * toDelete)
    {
        delete toDelete;
    };
}

//...

typedef std::vector<something>::iterator Iterator_T;
Iterator_t splitPoint = std::partition(v.begin(),v.end(),IsEven());
std::for_each(v.begin(), splitPoint, DeletePointer());
v.erase(v.begin(), splitPoint);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接