【问题标题】:Removing a vector element of object type using an iterator c++使用迭代器 C++ 删除对象类型的向量元素
【发布时间】:2017-10-15 19:54:13
【问题描述】:

我正在尝试编写一个函数,根据该向量元素的 account_name 从 listAccounts 中删除一个向量元素。我写了这个:

void Account::remove_account(string name) {

    auto iter = listAccounts.begin();

    for ( ; iter !=  listAccounts.end(); iter++) {
        if ((*iter).account_name == name) {
            listAccounts.erase(iter);
        }
    }

}

但是我从向量删除中得到了一个分段错误,据我了解,这意味着我试图访问我无权访问的内存,但我不确定如何正确编写它。

【问题讨论】:

  • 您想只删除一个元素还是删除所有具有给定值的元素?
  • 副本说明您的 for 循环在第一次擦除后变得无效。您需要在 if 语句中使用 break;
  • @Vlad 来自莫斯科 向量中有一个 account.name 等于 name 的元素。
  • @Captain Giraffe 我明白了,谢谢。

标签: c++ algorithm object vector erase


【解决方案1】:

一旦你删除了一个迭代器指向的元素,那个迭代器就失效了。 (对于std::vector,擦除元素之后的所有其他迭代器也变得无效)。并且递增取消引用无效的迭代器具有未定义的行为。

你可以这样做(假设只删除一个元素):

void Account::remove_account(string name) {
    auto iter = std::find_if(listAccounts.begin(), listAccounts.end(), 
                 [&](const auto& s){ return s.account_name == name; });
    if(iter != listAccounts.end())
        listAccounts.erase(iter);  
}

对于多个元素,这将是:

void Account::remove_account(string name) {
    for(auto iter = listAccounts.begin(); iter != listAccounts.end(); ){
        iter = std::find_if(iter, listAccounts.end(),
                    [&](const auto& s){ return s.account_name == name; });
        if(iter != listAccounts.end())
            iter = listAccounts.erase(iter);  
    }
}

【讨论】:

    【解决方案2】:

    如果容器被修改,迭代器变得无效。 有两个很好的解决方案:

    void Account::remove_account(const string& name) {
        auto iter = listAccounts.begin();
    
        while iter !=  listAccounts.end()) {
            if (iter->account_name == name) {
                iter = listAccounts.erase(iter);
            } else {
                ++iter;
            }
        }
    }
    
    // or
    void Account::remove_account(const string& name) {
        listAccounts.erase(
            std::remove_if(std::begin(listAccounts), std::end(listAccounts),
                           [&name](const auto& item) {
                               return item.account_name == name;
                           }),
            std::end(listAccounts));
    }
    

    【讨论】:

    • 在第二个解决方案中,您在向量上调用remove。我想你的意思是erase
    【解决方案3】:

    如果你只想删除一个元素,那么你可以写

    bool Account::remove_account( std::string &name ) 
    {
        auto it = std::find_if( listAccounts.begin(),
                                listAccounts.end(),
                                [&]( const auto &item )
                                {
                                    return item.account_name == name;
                                } );
    
        bool success = it != listAccounts.end();
    
        if ( success ) listAccounts.erase( it );
    
        return success;
    }
    

    至于你的代码然后在这个语句之后

    listAccounts.erase(iter);
    

    迭代器变得无效。所以你不能增加它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-15
      • 2016-09-24
      • 1970-01-01
      • 1970-01-01
      • 2017-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多