【问题标题】:Remove All Elements from unordered_set从 unordered_set 中删除所有元素
【发布时间】:2017-09-12 13:21:41
【问题描述】:

我已经看过这篇帖子Deleting elements from STL set while iterating

不过,我想了解为什么下面的代码会产生错误的结果。

int main() {
    unordered_set<int> adjacency;
    adjacency.insert(1);
    adjacency.insert(2);

    for (const auto& n : adjacency) {
        adjacency.erase(n);
    }

    cout <<"After removing all elements: " << endl;
    for (const auto& n : adjacency) {
        cout << n << " ";
    }
    cout << endl;

    return 0;
}

邻接包含1和2。通过for循环擦除所有元素后,它仍然包含元素1。为什么?

我在下面使用版本 (2) 擦除功能,因此规则“版本 (1) 和 (3) 返回一个迭代器,指向紧跟最后一个被擦除元素的位置。”不适用?

更新:不使用 clear() 的原因是它需要一个一个地删除元素来做一些其他的处理。

by position (1) 
iterator erase ( const_iterator position );
by key (2)  
size_type erase ( const key_type& k );
range (3)   
iterator erase ( const_iterator first, const_iterator last );

版本 (2) 返回已擦除元素的数量,在 unordered_set 容器(具有唯一值)中,如果存在值为 k 的元素(因此随后被擦除)则为 1,否则为零。

版本 (1) 和 (3) 返回一个迭代器,指向紧跟最后一个被擦除元素的位置。

谢谢!

【问题讨论】:

  • 如果你要删除集合中的所有元素,为什么不在循环之后简单的clear it
  • 我更新了问题
  • "the iterators and references to the elements removed are invalidated."将此规则应用于您的情况:代码使用了无效的迭代器。行为未定义。
  • 问题已更新。该规则似乎不适用于这里?
  • 基于范围的 for 循环在底层使用迭代器(请参阅 this),因此它适用于此

标签: c++11 unordered-set


【解决方案1】:

基于范围的 for 循环在底层使用迭代器, 所以你写的内容会导致未定义的行为。

如果你需要处理所有元素,然后删除一些 其中基于某些标准,有一种方法可以做到这一点 适用于所有容器:

for(auto it = adjacency.begin(); it != adjacency.end();)
{
    Process(*it);
    if (Condition(*it))
        it = adjacency.erase(it);
    else
        ++it;
}

如果您需要处理所有项目,然后全部删除,请执行此操作:

std::for_each(adjacency.begin(), adjacency.end(), &Process);
adjacency.clear();

【讨论】:

    【解决方案2】:

    正如雷蒙德指出的那样,您正在从自己的脚下拉出地毯。

    #include <iostream>
    #include <unordered_set>
    
    using namespace std;
    
    int main()
    {
        typedef unordered_set<int> adjacency_t;
        typedef adjacency_t::iterator adjacencyIt_t;
        adjacency_t adjacency;
        adjacency.insert(1);
        adjacency.insert(2);
    
        cout <<"Before: " << endl;
        for (const auto& n : adjacency) {
            cout << n << " ";
        }
        cout << endl;
    
        for (adjacencyIt_t i = adjacency.begin(); i!=adjacency.end(); /*empty*/)
        {
            // Do some processing on *i here.
            adjacency.erase(i++); // Don't erase the old iterator before using it to move to the next in line.
    
        }
    
        cout <<"After removing all elements: " << endl;
        for (const auto& n : adjacency) {
            cout << n << " ";
        }
        cout << endl;
    
        return 0;
    }
    

    【讨论】:

    • 谢谢,史蒂夫。您的代码有效。但是,“adjacency.erase(i++);”有什么区别?和“adjacency.erase(i); i++”?后者不起作用。
    • 那是因为用i调用erase后,i就失效了。
    • i++ 返回 i 的副本,然后递增 i。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-01
    • 1970-01-01
    • 2014-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多