簡體   English   中英

處理向量時如何為find和find_if使用正確的指針

[英]How to use correct pointer for find and find_if when dealing with vector

我有這樣的結構:

struct client
{
    string name;
    double money;
};

我也有2個謂詞:

bool less_10(const client& a)
{
    return a.money < 10;
}

bool not_a(const client& a)
{
    return a.name.at(0) != 'A';
}

在我的主要功能中,我用它來過濾存儲在向量client_list中的結果(每個人的錢<10(選擇1)或每個名字都不以A開頭的人(否則))

if (choice_filter == 1)
    {
        vector<client>::iterator it3;
        it3 = find_if(client_list.begin(), client_list.end(), less_10);
        while (it3 != client_list.end())
        {
            **client_list.erase(it3); 
            it3 = find_if(it3 + 1, client_list.end(), less_10);
        }
        client_list.erase(it3);**
    }

    else
    {
        vector<client>::iterator it4;
        it4 = find_if(client_list.begin(), client_list.end(), not_a);

        while (it4 != client_list.end())
        {
            **client_list.erase(it4);
            it4 = find_if(it4 + 1, client_list.end(), not_a);
        }
        client_list.erase(it4);**
}

我注意到,如果我先刪除,然后再查找,則我將丟失最后一個客戶端。 因此,我又增加了1行要擦除,但是由於迭代器現在位於末尾而無法擦除,因此該程序崩潰了。

有什么辦法可以解決這個問題? 我想繼續使用帶謂詞的find_if以及上面需要的while循環,因為它們是必需的。

正如其他人所說, std::remove_if是最好的解決方案。 如果您出於教學原因執行此操作(鑒於這些特定謂詞,我懷疑是這種情況):您的方向正確。 唯一的問題是client_list.erase使迭代器無效。 但是,由於它會在刪除元素后立即將迭代器返回到該元素,因此您可以使用類似以下內容的方法:

std::vector<Client>::iterator it 
    = std::find_if( client_list.begin(), client_list.end(), predicate );
while ( it != client_list.end() ) {
    it = client_list.erase( it );
    it = std::find_if( it, client_list.end(), predicate );
}

而且您不想在循環后調用擦除。 迭代器指定沒有要刪除的元素的結尾。

我也同意克里斯,使用std :: remove_if:

{
    remove_if(client_list.begin(), client_list.end(), less_10);
}

但是,如果您想重新發明輪子:

{
    vector<client>::iterator it3 = client_list.begin();
    while (true)
    {
        it3 = find_if(it3, client_list.end(), less_10);
        if (it3 == client_list.end()) {
            break;
        }
        it3 = client_list.erase(it3); 
    }
}

典型的方法是使用臨時向量:

vector<client> tmp;
for (...)
{
    if(predicate(it))
        tmp.push_back(*it);
}
client_list.swap(tmp);

這類似於克里斯在評論中建議的內容,盡管該解決方案將首先將元素移到向量的末尾,然后從那里截斷它們。 我不確定這是否不會改變順序,只需查看文檔即可。 但是,根據您的需要,兩者都可以完成工作。


如果您使用了一個不同的容器(例如list <>),而該容器沒有使delete()中的所有迭代器無效,則可以這樣做:

it = c.begin();
end = c.end();
while(it != end)
{
    if(predicate(*it))
    {
        c.erase(it++);
    }
    else
    {
        ++it;
    }
}

請注意,如果調用Erase(),則會使該迭代器仍然無效,因此該迭代器將首先遞增,並使用后綴增量使用前一個值調用Erase()。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM