C++ 如何使用反向迭代器调用擦除
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1830158/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to call erase with a reverse iterator
提问by 0xC0DEFACE
I am trying to do something like this:
我正在尝试做这样的事情:
for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
if ( *i == pCursor )
{
m_CursorStack.erase( i );
break;
}
}
However erase takes an iterator and not a reverse iterator. is there a way to convert a reverse iterator to a regular iterator or another way to remove this element from the list?
然而,擦除需要一个迭代器而不是一个反向迭代器。有没有办法将反向迭代器转换为常规迭代器或从列表中删除此元素的另一种方法?
回答by 0xC0DEFACE
After some more research and testing I found the solution. Apparently according to the standard [24.4.1/1] the relationship between i.base() and i is:
经过更多的研究和测试,我找到了解决方案。显然根据标准 [24.4.1/1] i.base() 和 i 之间的关系是:
&*(reverse_iterator(i)) == &*(i - 1)
(from a Dr. Dobbs article):
(来自Dobbs 博士的文章):
So you need to apply an offset when getting the base(). Therefore the solution is:
因此,您需要在获取 base() 时应用偏移量。因此解决方法是:
m_CursorStack.erase( --(i.base()) );
EDIT
编辑
Updating for C++11.
更新 C++11。
reverse_iterator i
is unchanged:
reverse_iteratori
不变:
m_CursorStack.erase( std::next(i).base() );
reverse_iterator i
is advanced:
reverse_iteratori
进阶:
std::advance(i, 1);
m_CursorStack.erase( i.base() );
I find this much clearer than my previous solution. Use whichever you require.
我发现这比我以前的解决方案清楚得多。使用任何你需要的。
回答by Andrey
Please note that m_CursorStack.erase( (++i).base())
may be a problem if used in a for
loop (see original question) because it changes the value of i. Correct expression is m_CursorStack.erase((i+1).base())
请注意,m_CursorStack.erase( (++i).base())
如果在for
循环中使用可能会出现问题(请参阅原始问题),因为它会更改 i 的值。正确的表达是m_CursorStack.erase((i+1).base())
回答by slashmais
... or another way to remove this element from the list?
...或从列表中删除此元素的另一种方法?
This requires the -std=c++11
flag (for auto
):
这需要-std=c++11
标志(用于auto
):
auto it=vt.end();
while (it>vt.begin())
{
it--;
if (*it == pCursor) //{ delete *it;
it = vt.erase(it); //}
}
回答by Gaetano Mendola
Funny that there is no correct solution on this page yet. So, the following is the correct one:
有趣的是,此页面上还没有正确的解决方案。因此,以下是正确的:
In case of the forward iterator the solution is straight forward:
对于前向迭代器,解决方案很简单:
std::list< int >::iterator i = myList.begin();
while ( ; i != myList.end(); ) {
if ( *i == to_delete ) {
i = myList.erase( i );
} else {
++i;
}
}
In case of reverse iterator you need to do the same:
在反向迭代器的情况下,您需要执行相同的操作:
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;
}
}
Notes:
笔记:
- You can construct a
reverse_iterator
from an iterator - You can use the return value of
std::list::erase
- 您可以
reverse_iterator
从迭代器构造一个 - 您可以使用返回值
std::list::erase
回答by etham
And here is the piece of code to convert the result of erase back to a reverse iterator in order to erase an element in a container while iterating in the reverse. A bit strange, but it works even when erasing the first or last element:
这是将擦除结果转换回反向迭代器的一段代码,以便在反向迭代时擦除容器中的元素。有点奇怪,但即使在擦除第一个或最后一个元素时它也能工作:
std::set<int> set{1,2,3,4,5};
for (auto itr = set.rbegin(); itr != set.rend(); )
{
if (*itr == 3)
{
auto it = set.erase(--itr.base());
itr = std::reverse_iterator(it);
}
else
++itr;
}
回答by Nismo
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--;
}
回答by Adam Rosenfield
While using the reverse_iterator
's base()
method and decrementing the result works here, it's worth noting that reverse_iterator
s are not given the same status as regular iterator
s. In general, you should prefer regular iterator
s to reverse_iterator
s (as well as to const_iterator
s and const_reverse_iterator
s), for precisely reasons like this. See Doctor Dobbs' Journalfor an in-depth discussion of why.
虽然使用reverse_iterator
'sbase()
方法并减少结果在这里有效,但值得注意的是,reverse_iterator
s 的状态与常规iterator
s 不同。一般来说,你应该更喜欢常规的iterator
s 而不是reverse_iterator
s(以及const_iterator
s 和const_reverse_iterator
s),正是出于这样的原因。有关原因的深入讨论,请参阅Dobbs 医生的日志。
回答by gavinbeatty
If you don't need to erase everything as you go along, then to solve the problem, you can use the erase-remove idiom:
如果您不需要在进行过程中擦除所有内容,那么要解决问题,您可以使用擦除-删除成语:
m_CursorStack.erase(std::remove(m_CursorStack.begin(), m_CursorStack.end(), pCursor), m_CursorStack.end());
std::remove
swaps all the items in the container that match pCursor
to the end, and returns an iterator to the first match item. Then, the erase
using a range will erase from the first match, and go to the end. The order of the non-matching elements is preserved.
std::remove
交换容器中匹配pCursor
到末尾的所有项目,并返回一个迭代器到第一个匹配项目。然后,erase
使用范围将从第一个匹配中删除,并转到最后。保留不匹配元素的顺序。
This might work out faster for you if you're using a std::vector
, where erasing in the middle of the contents can involve a lot of copying or moving.
如果您使用的是std::vector
,这对您来说可能会更快,因为在内容中间擦除可能涉及大量复制或移动。
Or course, the answers above explaining the use of reverse_iterator::base()
are interesting and worth knowing, to solve the exact problem stated, I'd argue that std::remove
is a better fit.
或者,当然,上面解释使用的答案reverse_iterator::base()
很有趣并且值得了解,为了解决所述的确切问题,我认为这std::remove
是更合适的。
回答by user1493570
Just wanted to clarify something: In some of the above comments and answers the portable version for erase is mentioned as (++i).base(). However unless I am missing something the correct statement is (++ri).base(), meaning you 'increment' the reverse_iterator (not the iterator).
只是想澄清一些事情:在上面的一些评论和答案中,擦除的便携式版本被称为 (++i).base()。但是,除非我遗漏了一些正确的语句是 (++ri).base(),这意味着您“增加”reverse_iterator(而不是迭代器)。
I ran into a need to do something similar yesterday and this post was helpful. Thanks everyone.
我昨天需要做类似的事情,这篇文章很有帮助。谢谢大家。
回答by fmmarques
To complement other's answers and because I stumbled upon this question whilst searching about std::string without much success, here goes a response with the usage of std::string, std::string::erase and std::reverse_iterator
为了补充其他人的答案,并且因为我在搜索 std::string 时偶然发现了这个问题,但没有取得多大成功,这里给出了使用 std::string、std::string::erase 和 std::reverse_iterator 的响应
My problem was erasing the an image filename from a complete filename string. It was originally solved with std::string::find_last_of, yet I research an alternative way with std::reverse_iterator.
我的问题是从完整的文件名字符串中删除图像文件名。它最初是用 std::string::find_last_of 解决的,但我用 std::reverse_iterator 研究了另一种方法。
std::string haystack("\\UNC\complete\file\path.exe");
auto&& it = std::find_if( std::rbegin(haystack), std::rend(haystack), []( char ch){ return ch == '\'; } );
auto&& it2 = std::string::iterator( std::begin( haystack ) + std::distance(it, std::rend(haystack)) );
haystack.erase(it2, std::end(haystack));
std::cout << haystack; ////// prints: '\UNC\complete\file\'
This uses algorithm, iterator and string headers.
这使用算法、迭代器和字符串标头。