IT Share you

부호없는 루프 변수를 사용한 역 반복

shareyou 2021. 1. 9. 10:55
반응형

부호없는 루프 변수를 사용한 역 반복


동료들과 size_t의 사용에 대해 논의 해 왔습니다. 발생한 한 가지 문제는 루프 변수가 0에 도달 할 때까지 감소시키는 루프입니다.

다음 코드를 고려하십시오.

for (size_t i = n-1; i >= 0; --i) { ... }

이로 인해 부호없는 정수 랩 어라운드로 인해 무한 루프가 발생합니다. 이 경우 무엇을합니까? 위의 코드를 작성하는 것은 쉽지 않고 실수를했는지 깨닫지 못하는 것 같습니다.

우리 팀의 두 가지 제안은 다음 스타일 중 하나를 사용하는 것입니다.

for (size_t i = n-1; i != -1 ; --i) { ... }

for (size_t i = n; i-- > 0 ; ) { ... }

하지만 다른 옵션이 있는지 궁금합니다 ...


개인적으로 좋아하게되었습니다.

for (size_t i = n; i --> 0 ;)

-1a) 재미 없음 , b) 상태 확인이 니모닉, c) 적절한 스마일리로 끝납니다.


부호없는 정수는 멋지게 래핑됩니다. 그들은 단지 산술 모듈로 2 N을 구현 합니다. 읽기 쉬운 관용구는 다음과 같습니다.

for (size_t i = n-1; i < n ; --i) { ... }

이것은 변수를 원하는 초기 값으로 설정하고 반복의 의미 (아래쪽)를 표시하며 처리하려는 값에 대한 조건을 정확하게 제공합니다.


  1. 루프를 알고리즘으로 대체하십시오.
  2. 정수 대신 역방향 반복기를 사용하십시오.
  3. (1) n은 카운트 다운하지만 루프 내부에서 i-1대신 i.

실수로 이와 같은 루프를 작성하는 것이 걱정된다면 일부 컴파일러는 그런 것에 대해 경고합니다. 예를 들어 gcc에는 -Wtype-limits옵션으로 활성화 된 경고가 있습니다 (에서도 활성화 됨 -Wextra).

x.c:42: warning: comparison of unsigned expression >= 0 is always true

표준 라이브러리 컨테이너를 사용하고 있습니까? 만약 그렇다면reverse_iterator

   vector<int> ivect;

   // push, push, push...

   vector<int>::reverse_iterator riter;
   for(riter=riter.rbegin(); riter!=ivect.rend(); ++riter)
   {
       //...
   }

원시 배열의 std::reverse_iterator경우 포인터 반복 자라는 점에 대한 키를 사용할 수 있습니다 .

int i[] = {1, 2, 3, 4};

typedef std::reverse_iterator<const int*> irevit;

irevit iter(i+4);
irevit end(i);
for(; iter != end; ++iter) {
    cout << *iter;
}

// Prints 4321

비 연속적인 객체 반복은 객체 포인터를 컨테이너 또는 배열에 저장하여 수행 할 수 있습니다.

struct Foo {
    Foo(int i) I(i) { }
    int I;
}

vector<Foo*> foos;
for(int i = 0; i < 10; ++i)
    foos.push_back(new Foo(i));

typedef vector<Foo*>::const_reverse_iterator frevit;

frevit iter(foos.rbegin());
for(; iter != foos.rend(); ++iter) {
    cout << (*iter)->I;
}

// Prints 9876543210

If you really want to use a naked size_t then why use all of this implicitly confusing -1 trickery in the other answers? The max value of size_t is explicitly available to use as your termination value:

int is[] = {1, 2, 3, 4};
int n = 3;

for (size_t i = n; i != std::numeric_limits<size_t>::max(); --i) {
    cout << is[i] << endl;
}

// prints 4321

i != -1 relies on the -1 being silently cast to a size_t, which seems fragile to me, so, of the alternatives you present, I'd definitely go with the post-decrement one. Another possibility (esp. if you don't actually need i in the loop body but just need to iterate on an array in reverse order) would be to wrap the array in a std::-like container and use an iterator on the wrapper, with the rbegin and rend methods. E.g., Boost.Array would support the latter choice.


Here is a pointer to a good discussion on this topic.

I would try:

for( size_t i = n; i != 0; i-- ) {
  // do stuff with array[ i - 1 ]
}

size_t i = n-1;

do  { 
  ...
} while ( i-- != 0);

You may wrap that with a if (n > 0) if necessary.


Yet another way (no signed/unsigned comparisons):

for (size_t i = n-1; i + 1 > 0; i--)

since

(i + 1 > 0) === (i > -1)

Another solution (available on POSIX compliant systems) that I found to be simple and effective is to replace size_t with ssize_t:

for (ssize_t i = n-1; i >= 0; --i) { ... }

On non-POSIX systems, ssize_t is not difficult to typedef: Alternative to ssize_t on POSIX-unconformant systems

ReferenceURL : https://stackoverflow.com/questions/3623263/reverse-iteration-with-an-unsigned-loop-variable

반응형