본문 바로가기
개발/C++

역방향 반복기로 지우기를 호출하는 방법

by MinorMan 2020. 9. 30.
반응형

<질문>

나는 다음과 같은 것을 시도하고 있습니다.

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

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


<답변1>

더 많은 연구와 테스트를 거쳐 해결책을 찾았습니다. 표준 [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() );

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


<답변2>

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


<답변3>

... 또는 목록에서이 요소를 제거하는 다른 방법?

여기에는 -std = c ++ 11 플래그 (자동의 경우)가 필요합니다.

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

<답변4>

아직이 페이지에 올바른 해결책이 없다는 것이 재밌습니다. 따라서 다음은 올바른 것입니다.

순방향 반복자의 경우 솔루션은 간단합니다.

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

역 반복자의 경우에도 동일하게 수행해야합니다.

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

메모:

  • 반복기에서 reverse_iterator를 생성 할 수 있습니다.
  • std :: list :: erase의 반환 값을 사용할 수 있습니다.

<답변5>

reverse_iterator의 base () 메서드를 사용하고 결과를 줄이는 것이 여기서 작동하지만 reverse_iterator가 일반 반복자와 동일한 상태를 갖지 않는다는 점에 주목할 가치가 있습니다. 일반적으로, 정확히 이와 같은 이유로 reverse_iterators (const_iterators 및 const_reverse_iterators뿐만 아니라)보다 일반 반복기를 선호해야합니다. 이유에 대한 심도있는 논의는 Doctor Dobbs의 저널을 참조하십시오.


<답변6>

typedef std::map 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--;
}

<답변7>

그리고 여기에 역방향으로 반복하는 동안 컨테이너의 요소를 삭제하기 위해 삭제 결과를 역방향 반복기로 변환하는 코드가 있습니다. 약간 이상하지만 첫 번째 또는 마지막 요소를 지울 때도 작동합니다.

std::set 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;
}

<답변8>

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

m_CursorStack.erase(std::remove(m_CursorStack.begin(), m_CursorStack.end(), pCursor), m_CursorStack.end());

std :: remove는 pCursor와 일치하는 컨테이너의 모든 항목을 끝까지 교체하고 첫 번째 일치 항목에 대한 반복자를 반환합니다. 그런 다음 범위를 사용하여 지우기는 첫 번째 일치에서 지워지고 끝으로 이동합니다. 일치하지 않는 요소의 순서는 유지됩니다.

std :: vector를 사용하는 경우이 작업이 더 빨리 처리 될 수 있습니다. 여기서 내용 중간에있는 지우기에는 많은 복사 또는 이동이 포함될 수 있습니다.

또는 물론 reverse_iterator :: base () 사용을 설명하는 위의 답변은 흥미롭고 알 가치가 있으며, 명시된 문제를 정확히 해결하기 위해 std :: remove가 더 적합하다고 주장합니다.


<답변9>

뭔가를 명확히하고 싶었습니다. 위의 주석과 답변 중 일부에서 지우기를위한 휴대용 버전은 (++ i) .base ()로 언급되었습니다. 그러나 내가 뭔가를 놓치지 않는 한 올바른 진술은 (++ ri) .base ()입니다. 이는 reverse_iterator (반복자가 아님)를 '증가'한다는 것을 의미합니다.

어제 비슷한 일을해야 할 필요가 생겼는데이 게시물이 도움이되었습니다. 모두 감사합니다.


<답변10>

다른 사람의 답변을 보완하기 위해 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\'

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


<답변11>

역 반복기는 사용하기 매우 어렵습니다. 그래서 그냥 일반 반복자를 사용했습니다. 'r'마지막 요소부터 시작합니다. 지울 것을 찾을 때. 지우고 다음 반복자를 반환합니다. 예를 들어 세 번째 요소를 삭제하면 현재 네 번째 요소를 가리 킵니다. 그리고 새로운 3rd. 따라서 왼쪽으로 이동하려면 1을 줄여야합니다.

void remchar(string& s,char c)
{      
    auto r = s.end() - 1;
    while (r >= s.begin() && *r == c)
    {
        r = s.erase(r);
        r -= 1;
    }
}
728x90

댓글