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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:19:18  来源:igfitidea点击:

How to call erase with a reverse iterator

c++

提问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 博士的文章):

alt text

替代文字

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 iis unchanged:

reverse_iteratori不变:

m_CursorStack.erase( std::next(i).base() );

reverse_iterator iis 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 forloop (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++11flag (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_iteratorfrom 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_iterators are not given the same status as regular iterators. In general, you should prefer regular iterators to reverse_iterators (as well as to const_iterators and const_reverse_iterators), for precisely reasons like this. See Doctor Dobbs' Journalfor an in-depth discussion of why.

虽然使用reverse_iterator'sbase()方法并减少结果在这里有效,但值得注意的是,reverse_iterators 的状态与常规iterators 不同。一般来说,你应该更喜欢常规的iterators 而不是reverse_iterators(以及const_iterators 和const_reverse_iterators),正是出于这样的原因。有关原因的深入讨论,请参阅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::removeswaps all the items in the container that match pCursorto the end, and returns an iterator to the first match item. Then, the eraseusing 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::removeis 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.

这使用算法、迭代器和字符串标头。