簡體   English   中英

向量擦除迭代器

[英]Vector erase iterator

我有這個代碼:

int main()
{
    vector<int> res;
    res.push_back(1);
    vector<int>::iterator it = res.begin();
    for( ; it != res.end(); it++)
    {
        it = res.erase(it);
        //if(it == res.end())
        //  return 0;
    }
}

“一個隨機訪問迭代器,指向函數調用擦除的最后一個元素之后的元素的新位置,如果操作擦除了序列中的最后一個元素,則該位置是向量結束。”

這段代碼崩潰了,但如果我使用if(it == res.end())部分然后返回,它就可以工作。 怎么來的? for 循環是否緩存res.end()所以不等於運算符失敗?

res.erase(it)總是返回下一個有效的迭代器,如果你擦除最后一個元素,它將指向.end()

在循環結束時++it總是被調用,所以你增加了.end()這是不允許的。

簡單地檢查.end()仍然會留下一個錯誤,因為你總是在每次迭代時跳過一個元素( it通過.erase()的返回“遞增”,然后再次通過循環)

你可能想要這樣的東西:

 while (it != res.end()) {
        it = res.erase(it);    
 }

擦除每個元素

(為了完整性:我假設這是一個簡化的例子,如果你只是想讓每個元素都消失而不必對其執行操作(例如刪除),你應該簡單地調用res.clear()

當您僅有條件地擦除元素時,您可能需要類似

for ( ; it != res.end(); ) {
  if (condition) {
    it = res.erase(it);
  } else {
    ++it;
  }
}
for( ; it != res.end();)
{
    it = res.erase(it);
}

或者,更一般的:

for( ; it != res.end();)
{
    if (smth)
        it = res.erase(it);
    else
        ++it;
}

因為 vector 中的方法 erase 返回傳遞的迭代器的下一個迭代器。

我將舉例說明如何在迭代時刪除向量中的元素。

void test_del_vector(){
    std::vector<int> vecInt{0, 1, 2, 3, 4, 5};

    //method 1
    for(auto it = vecInt.begin();it != vecInt.end();){
        if(*it % 2){// remove all the odds
            it = vecInt.erase(it); // note it will = next(it) after erase
        } else{
            ++it;
        }
    }

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;

    // recreate vecInt, and use method 2
    vecInt = {0, 1, 2, 3, 4, 5};
    //method 2
    for(auto it=std::begin(vecInt);it!=std::end(vecInt);){
        if (*it % 2){
            it = vecInt.erase(it);
        }else{
            ++it;
        }
    }

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;

    // recreate vecInt, and use method 3
    vecInt = {0, 1, 2, 3, 4, 5};
    //method 3
    vecInt.erase(std::remove_if(vecInt.begin(), vecInt.end(),
                 [](const int a){return a % 2;}),
                 vecInt.end());

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;

}

輸出aw如下:

024
024
024

更多的生成方法:

template<class Container, class F>
void erase_where(Container& c, F&& f)
{
    c.erase(std::remove_if(c.begin(), c.end(),std::forward<F>(f)),
            c.end());
}

void test_del_vector(){
    std::vector<int> vecInt{0, 1, 2, 3, 4, 5};
    //method 4
    auto is_odd = [](int x){return x % 2;};
    erase_where(vecInt, is_odd);

    // output all the remaining elements
    for(auto const& it:vecInt)std::cout<<it;
    std::cout<<std::endl;    
}

it++ 指令在塊的末尾完成。 因此,如果您要擦除最后一個元素,則嘗試增加指向空集合的迭代器。

使用現代 C++ 可以做的事情是使用“std::remove_if”和 lambda 表達式;

此代碼將刪除向量的“3”

vector<int> vec {1,2,3,4,5,6};

vec.erase(std::remove_if(begin(vec),end(vec),[](int elem){return (elem == 3);}), end(vec));

不要擦除然后增加迭代器。 無需增加,如果您的向量具有奇數(或偶數,我不知道)元素數,您將錯過向量的末尾。

在 for 循環的循環表達式中將it增加到(空)容器的末尾。

以下似乎也有效:

for (vector<int>::iterator it = res.begin(); it != res.end(); it++)
{
  res.erase(it--);
}

不知道這有沒有什么漏洞?

if(allPlayers.empty() == false) {
    for(int i = allPlayers.size() - 1; i >= 0; i--)
    {
        if(allPlayers.at(i).getpMoney() <= 0) 
            allPlayers.erase(allPlayers.at(i));
    }
}

這對我有用。 並且不需要考慮索引已經擦除。

作為對 crazylammer 答案的修改,我經常使用:

your_vector_type::iterator it;
for( it = res.start(); it != res.end();)
{
    your_vector_type::iterator curr = it++;
    if (something)
        res.erase(curr);
}

這樣做的好處是你不必擔心忘記增加迭代器,當你有復雜的邏輯時,它更不容易出錯。 在循環內部,curr 永遠不會等於 res.end(),並且無論您是否從向量中刪除它,它都將位於下一個元素。

暫無
暫無

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

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