【问题标题】:Is this map erasion safe? [duplicate]这种地图擦除安全吗? [复制]
【发布时间】:2015-12-24 02:14:59
【问题描述】:

我有一个带有这样的地图的 for 循环。

std::map<int,std::string> mymap = {{1,"a"},{2,"b"},{3,"c"}};

for(std::map<int,std::string>::iterator it = mymap.begin(); it!=mymap.end(); ++it)
{
    if(it->first==3)
    {
        mymap.erase(it);
    }
}

std::cout << mymap.rbegin()->second << std::endl;

如预期的那样,输出是“b”。问题是:这会以某种方式导致无限循环(或崩溃)吗?我是说之后

erase(it)

它是无效的迭代器。如果擦除的项目不是最后一个,它应该没问题,因为“它”在擦除之后递增,并且在评估条件时它最大指向 mymap.end()。但是,如果我擦除最后一个,则在擦除后 mymap.end() 应该在最后一个剩余项目之后,然后无论如何都会递增。它不能以某种方式超出范围吗?我不应该使用类似的东西

for(std::map<int,std::string>::iterator it = mymap.begin(); it!=mymap.end(); ++it)
{
    std::map<int,std::string>::const_iterator tempit = it;
    const bool lastItemErased = ++tempit == mymap.end();

    if(it->first==3)
    {
        mymap.erase(it);
    }

    if(lastItemErased) break;
}

为了安全?

注意:如果我尝试使用键 3 和 2 擦除元素,上述两种操作都将按预期运行。我不明白这怎么可能,为什么它不会崩溃。如何增加无效的迭代器?

更新:它必须与 c++03 一起使用。我这样初始化地图,以便更轻松地发布问题。

【问题讨论】:

  • 如果迭代器变得无效,那么根据定义,使用它是不安全的。这是“未定义”的行为,所以任何事情都可能发生。
  • 为了安全使用,请参阅此处文档中的示例:en.cppreference.com/w/cpp/container/map/erase
  • 在擦除后使用 rbegin 会从 map 中获取最后一个元素,那么您认为它为什么会崩溃?如果您使用的是前向迭代器,则必须按照链接到您的问题被标记为重复的问题的答案所指出的方式进行操作。

标签: c++ dictionary iterator undefined-behavior erase


【解决方案1】:

编辑:仅适用于 C++11 及更高版本。

std::map::erase 返回一个新的有效迭代器对象(即删除的元素之后的元素,在您的示例中为 mymap.end())。您应该使用该返回值:

for(std::map<int,std::string>::iterator it = mymap.begin(); it!=mymap.end();)
{
    if(it->first==3)
    {
        it = mymap.erase(it);
    }
    else
    {
        ++it;
    }
}

参考http://en.cppreference.com/w/cpp/container/map/erase

【讨论】:

  • 对不起。它必须与 c++03 一起使用。我这样初始化地图,以便更轻松地发布问题。
  • @LukasW 您的解决方案跳过了一些迭代
  • 你说得对,@Galik & Piotr,我会改正的。无论如何,新的 C++03 要求使这个答案毫无用处。
猜你喜欢
  • 2014-10-04
  • 1970-01-01
  • 1970-01-01
  • 2011-06-19
  • 2012-09-01
  • 1970-01-01
  • 2014-12-17
  • 2023-04-03
  • 1970-01-01
相关资源
最近更新 更多