【问题标题】:call a function, inside a for loop, to remove elements in a vector (or list)在 for 循环中调用函数以删除向量(或列表)中的元素
【发布时间】:2019-12-03 19:00:50
【问题描述】:
vector<node>::iterator it;
for(it;it!=vector_of_node.end();it++){
    if(it->get_name()=="MARIA"){
        vector_of_node.erase(it);
}

我希望我的代码目标很明确。我想从向量(在这种情况下为vector_of_nodes)中消除多个对象(在称为节点的类中描述)。 当我运行我的代码时,我没有从编译器得到任何错误,但我在运行时失败了。我确定错误出在我共享的这部分代码上。你能帮帮我吗?

【问题讨论】:

  • 从向量中擦除会使您正在使用的迭代器无效。您也许可以通过从末尾开始并从头开始来迭代使用索引。

标签: c++ class vector memory-management erase-remove-idiom


【解决方案1】:

通过一次擦除一个来消除向量中的多个对象是非常低效的。每个erase 调用都会将右侧的所有元素随机移动一个位置。已经有一个标准库模式可以更好地做到这一点,使用std::remove

std::erase(std::remove_if(vector_of_node.begin(),
                          vector_of_node.end(),
                          [](const node& n) { return n->get_name() == "MARIA"; }),
           vector_of_node.end());

std::remove_if 的结果是重新排列的向量,所有匹配都移到了末尾,它返回一个迭代器到第一个匹配。然后您调用std::erase 将它们全部删除。

【讨论】:

    【解决方案2】:

    使用您当前的方法,即逐个擦除向量中的元素,擦除后的所有元素都必须移动到向量的front。每次擦除元素的迭代都会执行此操作(仅当您擦除矢量的 back 时,元素才不会移动)。

    作为替代方案,您可能需要考虑Erase-remove idiom。如果您打算从 std::vector 中删除多个元素,则它更适合。

    // predicate (C++14 for generic lambda)
    auto is_maria = [](auto elem) {
       return elem.get_name() == "MARIA";
    };  
    
    auto end = std::remove_if(vector_of_node.begin(), vector_of_node.end(), is_maria); 
    vector_of_node.erase(end, vector_of_node.end());
    

    我们的想法是将要擦除的元素留在向量的后面,然后通过单个 erase() 调用从向量中删除,然后调用相应的重载,该重载采用范围(即迭代器对)。

    【讨论】:

      【解决方案3】:

      如果您在循环内增加迭代器,则可以在迭代时擦除,具体取决于您是否擦除元素。如果你擦除它,erase 方法会返回向量中的下一个迭代器,如果没有,则自行递增。此外,您需要将迭代器初始化为begin

      vector<node>::iterator it;
      for(it=vector_of_node.begin();it!=vector_of_node.end();){
          if(it->get_name()=="MARIA")
              it = vector_of_node.erase(it);
          else
              ++it;
      }
      

      【讨论】:

      • 所以使用擦除方法我可以指向向量的下一个元素并同时删除指向的元素?
      • @FrancescoDeSantis 没错。在内部,它首先将下一个迭代器保存在一个临时变量中,擦除给定的对象,然后返回下一个迭代器。
      • @foreknownas_463035818 抱歉,我不明白。你能解释一下你说的吗?
      • @foreknownas_463035818 哈哈我就是这么想的,我说的看不到链接
      • @foreknownas_463035818 我刚刚看到你的评论,别担心啊哈哈
      猜你喜欢
      • 2015-02-02
      • 1970-01-01
      • 2015-03-24
      • 2021-10-12
      • 1970-01-01
      • 1970-01-01
      • 2012-01-27
      • 2012-05-26
      相关资源
      最近更新 更多