如何使用反向迭代器调用erase

0xC*_*ACE 165 c++

我想做这样的事情:

for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
    if ( *i == pCursor )
    {
        m_CursorStack.erase( i );
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是擦除需要迭代器而不是反向迭代器.有没有办法将反向迭代器转换为常规迭代器或从列表中删除此元素的另一种方法?

0xC*_*ACE 165

经过一些研究和测试后,我找到了解决方案.显然根据标准[24.4.1/1],i.base()和i之间的关系是:

&*(reverse_iterator(i)) == &*(i - 1)
Run Code Online (Sandbox Code Playgroud)

(来自Dobbs博士的文章):

替代文字

所以你需要在获取base()时应用偏移量.因此解决方案是:

m_CursorStack.erase( --(i.base()) );
Run Code Online (Sandbox Code Playgroud)

编辑

更新C++ 11.

reverse_iterator i不变:

m_CursorStack.erase( std::next(i).base() );
Run Code Online (Sandbox Code Playgroud)

reverse_iterator i是高级的:

std::advance(i, 1);
m_CursorStack.erase( i.base() );
Run Code Online (Sandbox Code Playgroud)

我发现这比我以前的解决方案更清楚.使用您需要的任何一种.

  • 你应该注意一下你引用的文章 - 可移植的表达式应该是`m_CursorStack.erase((++ i).base())`(男人,用反向迭代器做这个东西会让我受伤...).还应该注意的是,DDJ文章被纳入了Meyer的"Effective STL"一书中. (26认同)
  • 我觉得这个图表更有说服力而不是有用.因为rbegin,ri和rend都*实际上*指向它们被指向的右边的元素.该图显示了你可以访问的元素,如果你是`*`它们,但我们正在谈论你指的是什么元素,如果你"`"它们,这是右边的一个元素.我不是` - (i.base())`或`(++ i).base()`解决方案的粉丝,因为它们会改变迭代器.我更喜欢`(i + 1).base()`也适用. (7认同)
  • 反向迭代器是liars ..当deferenced时,反向迭代器返回元素_before it_.[见这里](http://stackoverflow.com/a/14760316/111307) (4认同)
  • 为了绝对清楚,这种技术仍然不能用于普通的for循环(迭代器以正常方式递增).请参见http://stackoverflow.com/questions/37005449/how-to-call-erase-with-a-reverse-iterator-using-a-for-loop (4认同)

小智 15

请注意,m_CursorStack.erase( (++i).base())如果在for循环中使用可能会出现问题(请参阅原始问题),因为它会更改i的值.正确的表达是m_CursorStack.erase((i+1).base())

  • 你需要创建一个迭代器的副本并执行`iterator j = i; ++ j`,因为`i + 1`在迭代器上不起作用,但这是正确的想法 (4认同)
  • @bobobobo,你可以在Boost中使用`m_CursorStack.erase(boost :: next(i).base())`.或者在C++ 11`m_CursorStack.erase(std :: next(i).base())` (3认同)

Gae*_*ola 13

有趣的是,此页面上还没有正确的解决方案。因此,以下是正确的:

对于前向迭代器,解决方案很简单:

std::list< int >::iterator i = myList.begin();
while ( i != myList.end() ) {
  if ( *i == to_delete ) {
    i = myList.erase( i );
  } else {
    ++i;
  } 
}
Run Code Online (Sandbox Code Playgroud)

在反向迭代器的情况下,您需要执行相同的操作:

std::list< int >::reverse_iterator i = myList.rbegin();
while ( i != myList.rend() ) {
  if ( *i == to_delete ) {
    i = decltype(i)(myList.erase( std::next(i).base() ));
  } else {
    ++i;
  } 
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 您可以reverse_iterator从迭代器构造一个
  • 您可以使用返回值 std::list::erase

  • 此代码有效,但请解释为什么使用 next 以及如何安全地将正向迭代器转换为反向迭代器而不导致世界崩溃 (2认同)
  • @LefterisE 这不是演员阵容。它从迭代器中创建一个新的反向迭代器。这是反向迭代器的正常构造函数。 (2认同)

sla*_*ais 11

...或从列表中删除此元素的其他方法?

这需要-std=c++11标志(for auto):

auto it=vt.end();
while (it>vt.begin())
{
    it--;
    if (*it == pCursor) //{ delete *it;
        it = vt.erase(it); //}
}
Run Code Online (Sandbox Code Playgroud)

  • 谁保证您列表中的迭代器是有序的? (2认同)