如何使用迭代器删除 std::map 的元素?

发布于 2024-10-10 06:04:54 字数 44 浏览 7 评论 0原文

我想循环遍历 std::map 并根据内容删除项目。如何最好地做到这一点?

I would like to loop through an std::map and delete items based on their contents. How best would this be done?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

水晶透心 2024-10-17 06:04:54

如果您有一个兼容 C++11 的编译器,那么有一个简单的方法可以做到这一点:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       itr = myMap.erase(itr);
    } else {
       ++itr;
    }
}

这个想法是将迭代器从容器的开头向前移动到结尾,在每一步检查当前的键/值对是否应该被删除。如果是这样,我们使用 Erase 成员函数删除迭代的元素,然后该函数将迭代器返回到映射中的下一个元素。否则,我们将迭代器正常向前推进。

如果您没有符合 C++11 标准的编译器,或者您正在使用较旧的代码库,那么事情会有点棘手。在 C++11 之前,erase 成员函数不会返回指向映射中下一个元素的迭代器。这意味着为了在迭代时删除元素,您需要使用三部分的舞蹈:

  1. 复制当前迭代器。
  2. 将当前迭代器前进到下一个元素。
  3. 对旧迭代器的副本调用erase

此处显示:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       std::map<K, V>::iterator toErase = itr;
       ++itr;
       myMap.erase(toErase);
    } else {
       ++itr;
    }
}

此过程是必需的,因为如果您只是在迭代器上调用erase,您就会使其无效,这意味着诸如递增和递减之类的操作将导致未定义行为。上面的代码通过设置迭代器的副本来解决这个问题,前进 itr 使其位于下一个元素,然后删除迭代器的临时副本。

使用一些巧妙的技巧,可以以牺牲可读性为代价来缩小此代码。以下模式在较旧的 C++ 代码中很常见,但在 C++11 中不是必需的:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       myMap.erase(itr++);  // <--- Note the post-increment!
    } else {
       ++itr;
    }
}

这里使用后自增运算符是复制旧迭代器的巧妙方法(请记住,后缀 ++ 运算符返回原始迭代器值的副本),同时还推进旧迭代器。

If you have a C++11-compliant compiler, here's an easy way to do this:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       itr = myMap.erase(itr);
    } else {
       ++itr;
    }
}

The idea is to walk the iterator forward from the start of the container to the end, checking at each step whether the current key/value pair should be deleted. If so, we remove the element iterated over using the erase member function, which then returns an iterator to the next element in the map. Otherwise, we advance the iterator forward normally.

If you do not have a C++11-compliant compiler, or you're working with an older codebase, things are a bit trickier. Before C++11, the erase member function would not return an iterator to the next element in the map. This meant that in order to remove an element while iterating, you'd need to use a three-part dance:

  1. Copy the current iterator.
  2. Advance the current iterator to the next element.
  3. Call erase on the copy of the old iterator.

This is shown here:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       std::map<K, V>::iterator toErase = itr;
       ++itr;
       myMap.erase(toErase);
    } else {
       ++itr;
    }
}

This process was required because if you just called erase on the iterator, you'd invalidate it, meaning that operations like increment and decrement would lead to undefined behavior. The above code gets around this by setting up a copy of the iterator, advancing itr so that it's at the next element, then erasing the temporary copy of the iterator.

Using some Clever Trickiness, it's possible to shrink this code down at the expense of readability. The following pattern is common in older C++ code, but isn't necessary in C++11:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       myMap.erase(itr++);  // <--- Note the post-increment!
    } else {
       ++itr;
    }
}

The use of the post-increment operator here is a clever way of making a copy of the old iterator (remember that a postfix ++ operator returns a copy of the original iterator value) while also advancing the older iterator.

〆凄凉。 2024-10-17 06:04:54
for(MyMap::iterator it = mymap.begin(); it!=mymap.end(); ) {
  if(mycondition(it))
    it = mymap.erase(it);
  else
    it++;
}

编辑:似乎这仅适用于 MSVC

edit2:在 c++0x 中,这也适用于关联容器

for(MyMap::iterator it = mymap.begin(); it!=mymap.end(); ) {
  if(mycondition(it))
    it = mymap.erase(it);
  else
    it++;
}

edit: seems that this works in MSVC only

edit2: in c++0x this works for associative containers too

江城子 2024-10-17 06:04:54

这是一种简单的方法:

    int value_to_delete( 2 );
    for( std::map<int, int>::iterator i = mm.begin(); i != mm.end(); ) {
        if( i->second != value_to_delete ) {
            mm.erase( i++ ); // advance before iterator become invalid
        }
        else {
            ++i;
        }
    }

This is one simple way:

    int value_to_delete( 2 );
    for( std::map<int, int>::iterator i = mm.begin(); i != mm.end(); ) {
        if( i->second != value_to_delete ) {
            mm.erase( i++ ); // advance before iterator become invalid
        }
        else {
            ++i;
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文