Programing

역 반복자를 사용하여 지우기를 호출하는 방법

crosscheck 2020. 6. 6. 08:18
반응형

역 반복자를 사용하여 지우기를 호출하는 방법


나는 이런 식으로하려고합니다.

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

그러나 지우기는 역 반복자가 아닌 반복자를 사용합니다. 역 이터레이터를 일반 이터레이터로 변환하는 방법이나 목록에서이 요소를 제거하는 다른 방법이 있습니까?


더 많은 연구와 테스트를 거쳐 솔루션을 찾았습니다. 분명히 표준 [24.4.1 / 1]에 따르면 i.base ()와 i의 관계는 다음과 같습니다.

&*(reverse_iterator(i)) == &*(i - 1)

( 닥스 돕스 기사에서 ) :

대체 텍스트

따라서 base ()를 가져올 때 오프셋을 적용해야합니다. 따라서 해결책은 다음과 같습니다.

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() );

이전 솔루션보다 훨씬 명확합니다. 필요한 것을 사용하십시오.


참고 m_CursorStack.erase( (++i).base())A의 사용하는 경우 문제가 될 수 for는 i 값을 변경하기 때문에 (원래의 질문 참조) 루프를. 올바른 표현은m_CursorStack.erase((i+1).base())


... 또는이 요소를 목록에서 제거하는 다른 방법은 무엇입니까?

-std=c++11플래그에는 (for auto) 이 필요합니다 .

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

reverse_iteratorbase()방법을 사용하고 결과를 줄이는 것이 여기에서 효과가 있지만, reverse_iterators에 일반 iterators 와 동일한 상태가 부여되지 않았 음을 주목할 가치가 있습니다. 일반적으로 이와 같은 이유로 일반 iterators reverse_iterator에서 const_iterators 및 const_reverse_iterators s 선호해야합니다 . 이유에 대한 자세한 내용은 Dr Dobbs Journal참조하십시오 .


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--;
}

진행하면서 모든 것을 지울 필요가 없다면 문제를 해결하기 위해 지우기-삭제 관용구를 사용할 수 있습니다.

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.

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.

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.


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;
}

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

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).

나는 어제 비슷한 일을 할 필요가 있었고이 게시물이 도움이되었습니다. 모두 감사합니다.


다른 답변을 보완하고 많은 성공없이 std :: string을 검색하는 동안이 질문에 걸려 넘어 졌기 때문에 std :: string, std :: string :: erase 및 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\'

알고리즘, 반복자 및 문자열 헤더를 사용합니다.

참고 URL : https://stackoverflow.com/questions/1830158/how-to-call-erase-with-a-reverse-iterator

반응형