【问题标题】:Does std::map::erase(it++) maintain a valid iterator pointing to the next element in the map? [duplicate]std::map::erase(it++) 是否维护指向地图中下一个元素的有效迭代器? [复制]
【发布时间】:2014-06-14 18:00:49
【问题描述】:

我将 Xcode 与 C++ 11 一起用于 std::map。我地图中的某些元素有一个标志,表明它们需要被删除。

我想遍历地图,在 O(n) 时间内擦除标记的元素。对擦除的调用不返回迭代器。我见过某种擦除(it++)实现,但我没有证据表明这样的调用可以工作,因为迭代器将在擦除操作之后但在增量操作之前变得无效。

我当前的代码似乎效率很低。

for(auto it = myMap.begin(); it != myMap.end(); ++it)
{
    delete *it;
    myMap.erase(it);
    it = myMap.begin(); //how can I avoid iterating through the map again
}

【问题讨论】:

标签: c++ c++11 stl stdmap


【解决方案1】:

std::map::erase() 传递一个迭代器时,它会返回一个迭代器,指向被擦除元素之后的下一个元素。这使您可以继续迭代而无需重新开始。

试试这个:

auto it = myMap.begin();
while (it != myMap.end())
{
    if (it->flagged)
    {
        delete *it;
        it = myMap.erase(it);
    }
    else
        ++it;
}

【讨论】:

  • Xcode 对 C++ 11 标准的实现不是这样。
【解决方案2】:

来自在线文档:

“引用被函数删除的元素的迭代器、指针和引用无效。所有其他迭代器、指针和引用保持其有效性。”

所以也许是这样的:

for(auto it = myMap.begin(); it != myMap.end();)
{
    auto itPrev = it;
    ++it;

    if(shouldBeDeleted(*itPrev))
       myMap.erase(itPrev);
}

编辑:您提到的erase(it++) 想法实际上是可以的,因为在调用erase() 之前发生了增量(并返回旧的预增量值的副本)。它实际上相当于:

template<typename IteratorT>
IteratorT PostIncrement(IteratorT& it)
{
   auto copy = it;
   ++it;
   return copy;
}

for(auto it = myMap.begin(); it != myMap.end();)
   myMap.erase(PostIncrement(it));

这与另一个示例相同。顺便说一句,这就是为什么您应该通常在迭代器中使用前缀 ++;该复制操作是额外的开销,您通常不需要它。

【讨论】:

  • 你指的是什么在线文档?
  • 我看到的是这里:cplusplus.com/reference/map/map/erase。该页面还说 C++11 应该具有返回 iterators 的 erase 重载,但可能它们被排除在您正在使用的实现之外。
  • 好的,我没有注意到我可以点击那里的 C++11 选项卡。这似乎有道理,如果没有错误,我会将其标记为正确。
  • 用附加信息编辑了我的答案。
  • std::map::erase() 的版本接受一个交互器作为输入并返回一个迭代器到下一个元素作为输出在 C++11 中并不是新的,它也存在于早期版本中。
猜你喜欢
  • 2016-10-31
  • 2016-02-12
  • 2018-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-11
  • 2016-03-01
相关资源
最近更新 更多