如何用反向迭代器调用擦除
我正在尝试做这样的事情:
for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i ) { if ( *i == pCursor ) { m_CursorStack.erase( i ); break; } }
但是,擦除需要一个迭代器,而不是一个反向迭代器。 有没有办法将逆向迭代器转换为常规迭代器,或者有其他的方法来从列表中删除这个元素?
经过一些更多的研究和testing,我find了解决scheme。 显然根据标准[24.4.1 / 1],i.base()和i之间的关系是:
&*(reverse_iterator(i)) == &*(i - 1)
(来自Dr. Dobbs的文章 ):
所以你需要在获得base()时应用一个偏移量。 因此解决scheme是:
m_CursorStack.erase( --(i.base()) );
编辑
更新C ++ 11。
reverse_iterator i
是不变的:
m_CursorStack.erase( std::next(i).base() );
reverse_iterator i
是高级的:
std::advance(i, 1); m_CursorStack.erase( i.base() );
我觉得这比我以前的解决scheme更清晰。 使用您需要的任何一个。
请注意, m_CursorStack.erase( (++i).base())
可能是一个问题,如果在for
循环中使用(请参阅原始问题),因为它会更改i的值。 正确的expression式是m_CursorStack.erase((i+1).base())
…或者从列表中删除这个元素的另一种方法?
这需要-std=c++11
标志(对于auto
):
auto it=vt.end(); while (it>vt.begin()) { it--; if (*it == pCursor) //{ delete *it; it = vt.erase(it); //} }
在使用reverse_iterator
的base()
方法并在此处递减结果时,值得注意的是, reverse_iterator
不具有与常规iterator
相同的状态。 一般来说,您应该更喜欢使用常规iterator
来const_reverse_iterator
s(以及const_iterator
和const_reverse_iterator
),这是因为这样的原因。 看Dobbs医生的杂志深入讨论为什么。
typedef std::map<size_t, some_class*> TMap; TMap Map; ....... for( TMap::const_reverse_iterator It = Map.rbegin(), end = Map.rend(); It != end; It++ ) { TMap::const_iterator Obsolete = It.base(); // conversion into const_iterator It++; Map.erase( Obsolete ); It--; }
如果你不需要清除所有的东西,那么为了解决这个问题,你可以使用erase-remove idiom:
m_CursorStack.erase(std::remove(m_CursorStack.begin(), m_CursorStack.end(), pCursor), m_CursorStack.end());
std::remove
将容器中与pCursor
匹配的所有项目pCursor
到最后,并将迭代器返回到第一个匹配项目。 然后,使用范围的擦除将从第一次擦除擦除,并结束。 保留不匹配元素的顺序。
如果你使用的是std::vector
,那么在内容中删除可能涉及大量的复制或移动,这可能会更快。
或者当然,上面的解释reverse_iterator::base()
的使用的答案是有趣的,值得了解,为了解决确切的问题,我认为std::remove
更合适。
只是想澄清一些事情:在上面的一些评论和回答中,擦除的可移植版本被提及为(++ i).base()。 但是,除非我错过了正确的语句是(++ ri).base(),这意味着你“增加”了reverse_iterator(而不是迭代器)。
我遇到了需要做类似的事情昨天,这个post是有帮助的。 感谢大家。