使用迭代器 C++ 删除对象类型的向量元素

Posted

技术标签:

【中文标题】使用迭代器 C++ 删除对象类型的向量元素【英文标题】:Removing a vector element of object type using an iterator 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 我明白了,谢谢。 【参考方案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);

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

【讨论】:

以上是关于使用迭代器 C++ 删除对象类型的向量元素的主要内容,如果未能解决你的问题,请参考以下文章

C++ 字符串向量和数组的一些术语

C++ 字符串向量和数组的一些术语

C++ 字符串向量和数组的一些术语

练笔-字符串,向量和数组6

3 字符串向量和数组

C++ STL与迭代器