program tip

STL 컨테이너의 끝 반복자와 동일한 반복기를 증가 시키면 어떻게 되나요?

radiobox 2020. 12. 5. 09:33
반응형

STL 컨테이너의 끝 반복자와 동일한 반복기를 증가 시키면 어떻게 되나요?


벡터의 마지막 요소를 가리킬 때 반복기를 2 씩 증가 시키면 어떻게됩니까? 이 질문 에서는 두 가지 요소로 반복기를 STL 컨테이너로 조정하는 방법을 묻는 두 가지 접근 방식이 제공됩니다.

  • 산술 연산자 형식을 사용하십시오-+ = 2 또는 ++ 두 번
  • 또는 std :: advance () 사용

반복기가 STL 컨테이너의 마지막 요소 또는 그 이상을 가리킬 때 엣지 케이스에 대해 VC ++ 7로 둘 다 테스트했습니다.

vector<int> vec;
vec.push_back( 1 );
vec.push_back( 2 );

vector<int>::iterator it = vec.begin();
advance( it, 2 );
bool isAtEnd = it == vec.end(); // true
it++; // or advance( it, 1 ); - doesn't matter
isAtEnd = it == vec.end(); //false
it = vec.begin();
advance( it, 3 );
isAtEnd = it == vec.end(); // false

벡터와 다른 컨테이너를 순회 할 때 vector :: end ()와 비교하라는 조언을 몇 번 보았습니다.

for( vector<int>::iterator it = vec.begin(); it != vec.end(); it++ ) {
    //manipulate the element through the iterator here
}

반복자가 루프 내부의 마지막 요소를 지나서 진행되면 for-loop 문의 비교는 false로 평가되고 루프는 정의되지 않은 동작으로 계속 진행됩니다.

이터레이터에서 advance () 또는 어떤 종류의 증분 연산을 사용하고 컨테이너의 끝을 지나가도록하면이 상황을 감지 할 수 없다는 것을 올바르게 이해합니까? 그렇다면 그러한 발전을 사용하지 않는 것이 가장 좋은 방법은 무엇입니까?


다음은 Nicolai Josuttis 책의 인용문입니다.

advance ()는 시퀀스의 end ()를 교차하는지 여부를 확인하지 않습니다 (일반적으로 반복기가 작동하는 컨테이너를 모르기 때문에 확인할 수 없습니다). 따라서이 함수를 호출하면 시퀀스의 끝에 대해 ​​++ 연산자를 호출하는 것이 정의되지 않았기 때문에 정의되지 않은 동작이 발생할 수 있습니다.

즉, 범위 내에서 반복기를 유지하는 책임은 전적으로 호출자에게 있습니다.


아마도 다음과 같은 것이 있어야합니다.

template <typename Itr>
Itr safe_advance(Itr i, Itr end, size_t delta)
{
    while(i != end && delta--)
        i++;
    return i;
}

당신은 때이 오버로드 할 수 iterator_category<Itr>있습니다 random_access_iterator다음과 같은 것을 할 :

return (delta > end - i)? end : i + delta;

반복기 (it)와 vec.begin ()에서 반복기 사이의 "거리"함수를 사용하여 벡터의 크기 (size ()로 획득)와 비교할 수 있습니다.

이 경우 for 루프는 다음과 같습니다.

for (vector<int>::iterator it = vec.begin(); distance(vec.begin(), it) < vec.size(); ++it)
{
     // Possibly advance n times here.
}

Marijn이 제안한 코드는 약간 잘못되었습니다 (curiousguy가 지적했듯이).

마지막 줄의 올바른 버전은 다음과 같습니다.

bool isPastEnd = it >= vec.end();

Boost.Range를 살펴 보는 것이 좋습니다 .
사용하는 것이 더 안전 할 수 있습니다.
또한 C ++ 0x에 있습니다.


for 문에서 더 많은 비교를 수행 할 수도 있습니다.

for( vector<int>::iterator it = vec.begin(); it != vec.end() && it+1 != vec.end(); it+=2 ) {
    //manipulate the element through the iterator here
}

I don't know how this would perform vs Kostas's suggestion, but it feels like it would be better for a small increment. Of course it would be pretty unmaintainable for a large increment since you need a check for each, but it is another option.

I would definitely avoid it if at all possible. If you really need to increment by 2 values at a time, then consider having a vector of std::pair or a vector of a struct with 2 elements.


container.end() -- the element just past the end -- is the only defined exterior value.

A checked iterator will fault on what is essentially an out-of-range access, but that isn't terribly helpful (especially as the default behaviour is to end the program).

I think the best practice is "don't do that" -- either check every value of the iterator (preferably in something wrapped as a filter), and only operate on interesting entries, or use the index explicitly with

for(int i = 0; i < vec.size(); i+=2) {...}

Even though this question is half a year old, it might still be useful to mention the use of comparison operators > and < to check if you iterated past the end (or the start when iterating back) of the container. For example:

vector<int> vec;
vec.push_back( 1 );
vec.push_back( 2 );

vector<int>::iterator it = vec.begin();

it+=10; //equivalent to advance( it, 10 )
bool isPastEnd = it > vec.end(); //true

참고URL : https://stackoverflow.com/questions/1057724/what-happens-if-you-increment-an-iterator-that-is-equal-to-the-end-iterator-of-a

반응형