在基于范围的“for”循环中删除 std::map 的节点

问题描述 投票:0回答:2

我需要检查 std::map 的数据,并删除其中一些。 我正在使用基于范围的“for”循环,如下所示:

std::map<int, string> data { { 1, "name1" }, { 2, "name2" }, { 3, "name3" }, };

for( auto&[id, name] : data )
  if( id == 2 )
    data.erase( id );

这个方法正确吗?它会使循环崩溃或导致错误的循环时间吗?

c++ for-loop iteration stdmap range-based-loop
2个回答
1
投票

不,这个方法不正确。 range-for 循环在内部使用迭代器来驱动循环。如果通过删除元素来修改

data
,这将使现有迭代器无效并导致未定义的行为。你不能这样做。

你的特定示例有点太微不足道了——甚至没有循环的意义,因为你可以只做

data.erase(2);
而无需搜索整个地图。这样效率也更高。

如果您确实需要在循环时删除元素,

std::map::erase
的文档包含一个示例,详细说明了如何完成此操作。

如果您确实决定使用 range-for,那么您需要单独存储要擦除的键,然后在第二步中执行此操作。或者,您可以构建一个新地图,并

std::move
将您希望保留的数据放入其中,前提是您不修改原始地图的拓扑。

正如另一位用户评论的那样,另一个选项是

std::erase_if
——如果循环的唯一目的是验证内容,这将是最好的解决方案。在这种情况下,您可以放弃循环并使用
erase_if
进行验证——这可能是最有效的。


0
投票

不,这不是正确的方法。您想要学习的模式是:

std::map<int, string> data { { 1, "name1" }, { 2, "name2" }, { 3, "name3" }, };

for(auto it = data.begin(); it != data.end(); )
{
    if( it->first == 2 )
    {
        it = data.erase( it );
    }
    else
    {
        it++;
    }
}
return 0;

注意循环语句中缺少迭代器增量。相反,我们在删除后更新它,或者以其他方式增加它。

© www.soinside.com 2019 - 2024. All rights reserved.