문제

어떤 이유로 다음 코드가 실패합니다. Base () 메소드를 사용하여 REVERSE_ITERATOR를 간단히 지울 수는 없습니다.

#include <set>
#include <iostream>

int main()
{
    std::set<int> setOfInts;
    setOfInts.insert(1);
    setOfInts.insert(2);
    setOfInts.insert(3);

    std::set<int>::reverse_iterator rev_iter = setOfInts.rbegin();
    std::set<int>::reverse_iterator nextRevIter = setOfInts.rbegin();
    ++nextIter;

    while ( rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
        {
            // SEGFAULT HERE
            setOfInts.erase( rev_iter.base());
        }
        rev_iter = nextRevIter;
        ++nextRevIter;
    }

}

위의 일을 어떻게 올바르게 하는가? 지우고 싶은 것에 해당하는 reverse_iterator가 주어지면 어떻게 지우십니까?

Erase는 불행히도 Reverse_iterators를 사용하지 않습니다. 그것은 진짜를 원합니다.

도움이 되었습니까?

해결책

분명히 솔루션은 Base () 리턴이 1 꺼짐입니다. reverse_iterator에 대한 다음 아이덴티티는 다음과 같습니다.

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

다시 말해, REVERSE_ITERATOR는 항상 정규 반복자를 통과합니다. 이유가 확실하지 않습니다.

GCC에서

단순히 변경됩니다

        // SEGFAULT HERE
        setOfInts.erase( rev_iter.base());

에게

        // WORKS!
        setOfInts.erase( --rev_iter.base());

위의 정체성이 왜 의미가 있는지 궁금합니다.

Visual Studio에서

직장으로 돌아와서 Visual Studio에서 이것을 시도하면서 위의 솔루션이 효과가 없다는 것을 알았습니다. "Nextiter"는 지우기에 무효가됩니다. 대신, 위와 같은 다음 반복자를 유지하는 대신 다음 반복자를 얻으려면 지우기에서 임시를 절약해야합니다.

  set<int>::iterator tempIter = setOfInts.erase(--rev_iter.base());
  rev_iter = setOfInts.erase(tempIter);

따라서 최종 솔루션은입니다

int main()
{
    using namespace std;

    set<int> setOfInts;
    setOfInts.insert(1);
    setOfInts.insert(2);
    setOfInts.insert(3);

    set<int>::reverse_iterator rev_iter = setOfInts.rbegin();

    while ( rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
        {
            cout << "Erasing : " << *rev_iter;
            set<int>::iterator tempIter = setOfInts.erase( --rev_iter.base());
            rev_iter = set<int>::reverse_iterator(tempIter);            
        }
        else
        {
            ++rev_iter;
        }
    }   

}

연관 컨테이너는 반복자를 지우기에서 반환하지 않습니다. 따라서이 솔루션은지도, 멀티 맵 등에 작동하지 않습니다.

다른 팁

리버스 반복기를 반복하고 컨테이너를 수정하기 위해 Base ()를 사용하려면 항상 reverse_iterator는 항상 원래 순서의 다음 반복기를 기반으로합니다. 직관적이지 않지만 실제로 코드를 더 간단하게 만듭니다.

#include <set>
int main()
{
    std::set<int> setOfInts;
    setOfInts.insert(1);
    setOfInts.insert(2);
    setOfInts.insert(3);

    typedef std::set<int>::reverse_iterator RevIter;

    RevIter rev_iter = setOfInts.rbegin();
    while (rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
            setOfInts.erase(--rev_iter.base());

        ++rev_iter;
    }
}

이 예에서는 기본 반복기가 무효화되지 않기 때문에 "다음"반복자를 유지할 필요가 없습니다! (우리는 일반적인 반복자를 다룰 때 필요합니다.)

리버스 반복자의 동작은 단일 항목으로 치료할 때 이상한 오프별 어려움을 야기하지만 실제로는 범위를 단순화합니다.

riValue = find(riEnd.base(), riBegin.base(), value);

정확히 동일한 객체 (역 순서)를 사용하고 있습니다.

iValue = find(riBegin, riEnd, value);

1에서 지도 :: 지우기, 우리는 단지 필요한 것을 알고 있습니다 iterator;

2에서 reverse_iterator ::베이스, 우린 알아 &*(reverse_iterator ( i ) ) == &*( i – 1 ).

따라서 "r_v"(및 "current-1")로 가리키는 요소를 지우기 위해 (-r_v.base ())을 지울 수 있습니다.

            r_v+1            r_v          r_v-1
           current-2      current-1      current

부르다 erase 반복자 자체와 함께 (사용할 필요가 없습니다 base).

#include <set>
#include <iostream>

int main()
{
    std::set<int> setOfInts;
    setOfInts.insert(1);
    setOfInts.insert(2);
    setOfInts.insert(3);

    std::set<int>::reverse_iterator rev_iter = setOfInts.rbegin();

    while (rev_iter != setOfInts.rend())
    {
        // Find 3 and try to erase
        if (*rev_iter == 3)
        {
            rev_iter = setOfInts.erase(rev_iter);
        }
        else
        {
            ++rev_iter;
        }
    }
}

또한 별도의 "다음"반복자가 필요하지 않습니다 (위의 변경 사항 참조). 이 작업을 수행하는 더 좋은 방법은 사용하는 것입니다. std::remove_if (또는 그와 같은 기능).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top