'for'루프에서 조건으로 '<'대 '! ='?


31

다음과 같은 for루프 가 있다고 가정하십시오 .

for (int i = 0; i < 10; ++i) {
    // ...
}

일반적으로 다음과 같이 쓸 수 있습니다.

for (int i = 0; i != 10; ++i) {
    // ...
}

최종 결과는 동일하므로 다른 것을 사용하는 것에 대한 실제 주장이 있습니까? 개인적으로 나는 i어떤 이유로 haywire가되어 값 10을 건너 뛰는 경우를 위해 전자를 사용합니다 .

* 매직 넘버의 사용을 실례하지만, 이것은 단지 예일뿐입니다.


18
이들 중 하나에 대한 최상의 솔루션은 화살표 연산자를 사용하는 것입니다.int i = 10; while(i --> 0) { /* stuff */ }
corsiKa

@glowcoder 화살표 연산자는 내가 제일 좋아하는
카슨 마이어스

3
@glowcoder, 멋지지만 뒤에서 통과합니다. 항상 그런 것은 아닙니다.

2
@SuperElectric, 그것은 다음과 같이 분석합니다while ((i--) > 0)
Kristopher Johnson

17
센서 입력에 대한 while 루프 테스트가! = MAX_TEMP 인 산업 사고에 대한 (아마도 묵시적인) 이야기가 있습니다. 불행하게도 언젠가는 센서 입력이 MAX_TEMP를 통과하지 않고 MAX_TEMP보다 작고 MAX_TEMP보다 컸습니다. 프로세스가 감지되지 않고 과열되어 화재가 발생했습니다. 때로는! =와 <사이에 차이가 있습니다.
Charles E. Grant

답변:


59

둘 중 하나를 선택 해야하는 이유는 의도 때문이며 , 그 결과 가독성 이 향상 됩니다.

의도 : 루프는 i10보다 작지 않아야하며 10 i과 같지 않아야합니다. 후자는이 특정 경우에 동일 할 수 있지만, 이것이 의미하는 바가 아니므로 그렇게해서는 안됩니다. 그런 식으로 작성하십시오.

가독성 : 의미를 적어 놓은 결과는 이해하기도 쉽다는 것입니다. 예를 들어,을 사용하는 경우 i != 10코드를 읽는 사람이 루프 내부에 i10보다 큰 방법 이 있고 루프가 계속되어야 하는지 궁금해 할 수 있습니다 (btw : 반복자의 머리가 아닌 다른 곳에서 반복자와 엉망이되는 것은 나쁜 스타일입니다) - for하지만 , 이것이 사람들이 그렇게하지 않는다는 것을 의미하는 것은 아니며 결과적으로 관리자가 그것을 기대한다는 것을 의미합니다).


3
아니오, i"10보다 작은" 루프는 실행되지 않아야하며 (이 경우) 상한에 도달하지 않는 한 실행되어야합니다. 는 C ++ 간격 / 반복자 범위의 이론적 근거를 사용하는 경우, 그것은을 통해이를 표현하기 위해 훨씬 더 논리적이다 !=보다 <.
Konrad Rudolph

14
@ Konrad 나는 전혀 동의하지 않습니다. 요점은 교의적인 것이 아니라 조건의 의도를 가장 잘 나타내는 구성을 선택하는 것입니다. 따라서 0에서 시작하여 위로 움직이는 것을 반복하면 <실제로 정확하게 표현합니다.
Deckard

6
@ Konrad, 당신은 요점이 없습니다. 이 루프의 증가 연산자를 사용하면 루프 조건이 ID 비교가 아니라 상한임을 알 수 있습니다. 감소하고 있다면 하한이 될 것입니다. 순서가없는 컬렉션을 반복하는 경우 정체성이 올바른 조건 일 수 있습니다.
Alex Feinman

3
@Alex 증가는 내 요점이 아니었다. 간격도 필요하지 않습니다 주문을. 그것은 끝까지 도달 때까지 ... 반복적으로 반복 됩니다. 예를 들어, 해시 세트의 요소 C ++에서는 반복자와 for루프를 사용하여이 작업을 수행 합니다. <여기서 사용하는 것은 어리석은 일입니다. 또한 Deckard는이를 인정하는 것 같습니다. 나는 내 의견에 대한 그의 의견에 매우 동의한다.
Konrad Rudolph

1
체이스 포인터와 함께 로터리 버퍼를 사용하는 경우 반드시!=
SF

48

<패턴은 증가 정확히 1을 수없는 일 경우에도 일반적으로 사용할 수 있습니다.

이를 통해 실제로 수행되는 방법에 관계없이 루프를 수행하는 단일 공통 방법이 가능합니다.


6
또한 i필요한 경우 루프 내부를 완전히 안전하게 수정할 수 있습니다.
Matthew Scharley

1
또는 'i'가 완전히 안전하지 않게 수정 된 경우 ... 다른 팀에 이상한 서버 문제가 발생했습니다. 100 % CPU 사용량을 계속보고했으며 서버 나 모니터링 시스템에 문제가 있어야합니까? 아니요, 우리가 이야기하는 것과 동일한 문제로 '전문가 선임 프로그래머'가 작성한 루프 조건을 발견했습니다.
jqa

12
<시퀀스에서 반복자와 같은 모든 C ++ for 루프가를 사용할 수있는 것은 아니라는 점을 제외하고는 C ++에서 루프 !=를 수행하는 단일 공통 방법입니다.
David Thornley

@ SnOrfus : 나는 그 의견을 파싱하지 않습니다. 일반적으로 반복자를 너무 많이 늘리면 예외가 발생하지 않습니다 (더 구체적인 상황이 있지만).
David Thornley

글쎄, 내가 따라 <가 하나의 키 입력 대신에이 필요하기 때문에 패턴 >과 패턴, 그리고 네 !=. 실제로 OCD와 같은 효율성의 문제입니다.
Spoike

21

C ++에서 Scott Myers의보다 효과적인 C ++ (항목 6)의 권장 사항은 반복자와 정수 인덱스에 대해 동일한 구문을 사용하므로 int반복자와 이터레이터 간에 원활하게 교환 할 수 있다는 의미가 없기 때문에 이유가없는 한 항상 두 번째를 사용해야 합니다. 구문의 변화없이.

다른 언어에서는 이것이 적용되지 않으므로 <Thorbjørn Ravn Andersen의 지적 때문에 아마도 바람직하다고 생각 합니다.

그런데, 다른 날까지 나는 다른 개발자와 함께이 문제를 논의했다 그는 선호하는 이유 말했다 <이상이 !=있기 때문입니다 i힘 실수 하나 이상 씩 증가하고, 그 휴식의 조건이 충족되지 발생할 수 있습니다; 그건 말도 안되는 IMO입니다.


17
"무의미한 부하"... 실수로 루프 본문에 여분의 i ++가있는 날까지.

2
+1, 특히 "넌센스의로드"에 해당합니다. 루프 바디가 실수로 카운터를 증가 시키면 훨씬 더 큰 문제가 있습니다.
Konrad Rudolph

12
@B 타일러, 우리는 인간 일 뿐이고 이전에는 더 큰 실수가있었습니다. 이전 <보다 더 방어적인 프로그래밍을 고려하십시오 !=.

2
@ Thorbjørn Ravn Andersen-나는 당신에게 동의하지 않는다고 말하는 것이 아닙니다. <더 방어 적이며 동료가 글을 쓰면 싫어합니다 !=. 그러나 !=C ++ 의 경우 가 있으며 그것이 내가 제시 한 것입니다.

9
우연한 추가로 끝나는 시나리오 i++는 while 루프를 for 루프로 변경할 때입니다. 반복 횟수의 절반을 갖는 것이 (가까운) 무한 루프보다 나은지 확실하지 않습니다. 후자는 아마도 버그를 더 분명하게 만들 것입니다.
ak2

12

내 생각에 (i <10)을 사용하는 것이 더 안전한 방법입니다. 그것은 10보다 크거나 같은 모든 잠재적 종료 사례를 포착합니다. 다른 경우와 대조하십시오 (i! = 10); i가 정확히 10 일 때 가능한 종료 사례를 하나만 잡습니다.

이것의 부산물은 가독성을 향상 시킨다는 것입니다. 또한 증분이 다른 1 인 경우 종료 사례를 작성할 때 실수 할 경우 문제가 발생할 가능성을 최소화하는 데 도움이됩니다.

치다:

1) for (i = 1; i < 14; i+=2)

2) for (i = 1; i != 14; i+=2)

두 경우 모두 결함이 있거나 잘못되었을 수 있지만 두 번째 경우는 종료되지 않으므로 더 잘못 될 수 있습니다. 첫 번째 경우는 종료되며 14가 잘못된 숫자 일지라도 올바른 자리에서 종료 될 가능성이 더 높습니다 (15가 더 낫습니다).


첫 번째 경우가 옳을 수도 있습니다! 14보다 작은 모든 자연수를 반복하려면이를 표현하는 더 좋은 방법이 없습니다. "적절한"상한 (13)을 계산하는 것은 어리석은 일입니다.
maaartinus

9

아직 아무도 생각해 오지 않은 것 같은 또 다른 대답이 있습니다. for시퀀스를 반복해야하는 경우 루프를 사용해야합니다 . !=루프의 종료 조건을 나타내는 가장 간결한 방법은 사용 입니다. 그러나 덜 제한적인 연산자를 사용하는 것은 매우 일반적인 방어 프로그래밍 관용구입니다. 정수의 경우 중요하지 않습니다-더 구체적인 예가 없으면 개인적인 선택 일뿐입니다. !=다른 사람들이 언급 한 이유로 사용하려는 반복자가있는 콜렉션을 반복합니다 . float또는의 시퀀스를 고려 double하면 !=모든 비용 을 피하려고합니다 .

내가 지적하고 싶은 for것은 시퀀스를 반복해야 할 때 사용됩니다. 생성 된 시퀀스에는 시작 지점, 간격 및 종료 조건이 있습니다. 이들은 for진술 내에 간결하게 지정되어 있습니다. (1)의 단계 부분을 포함하지 for않거나 (2) true보호 조건 과 같은 것을 지정 하면 for루프를 사용해서는 안됩니다 !

while루프는 특정 조건이 충족되는 동안 처리를 계속하는 데 사용됩니다. 시퀀스를 처리하지 않으면 while대신 루프를 원할 것입니다. 가드 조건 인수는 여기에서 비슷하지만 a whilefor루프 사이의 결정은 매우 의식적인 것이어야합니다. whileIMO C ++ 서클 이해하에 루프이다.

항목 모음 (가장 일반적인 for루프 사용법)을 처리하는 경우 보다 전문화 된 방법을 사용해야합니다. 불행히도 std::for_each여러 가지 이유로 C ++에서 상당히 고통 스럽습니다. 많은 경우에 for독립형 기능 (약간 고통 스럽지만) 으로 루프 본체를 분리하면 훨씬 더 깨끗한 솔루션이됩니다. 컬렉션을 작업 할 때, 고려 std::for_each, std::transform또는 std::accumulate. 이러한 방식으로 표현할 때 많은 알고리즘의 구현이 간결하고 명확 해집니다. 루프 본문을 별도의 함수 / 방법으로 분리하면 알고리즘, 입력 요구 사항 및 결과에 집중하게됩니다.

자바, 파이썬, 루비, 또는 사용하는 경우 C + +0을 , 당신은 적절한 수집 이용해야 foreach는 루프를. C ++ 컴파일러가이 기능을 구현함에 따라 for이러한 유형의 토론과 마찬가지로 많은 루프가 사라집니다.


2
"그러나 덜 제한적인 연산자를 사용하는 것은 매우 일반적인 방어 프로그래밍 관용구입니다." 이것은 다소 요약합니다.
James P.

에 비교하여 의도의 차이를 discussin +1 while, forforeach(또는 언어 equivilant)
케빈 Peno

엄밀히 말하면, 특정 조건이 될 때까지 루프 처리를 계속 사용 하지 만났다while
알니 타크

@Alnitak-D' oh ... 나는 그것을 고칠 것이다 :)
D.Shawley

"덜 제한적"이라는 두 가지 가능한 의미에 혼동되어있었습니다. 즉, 전달하는 값 <에 관대 한 연산자 ( ) 또는 실패한 값에 관대 한 연산자 ( )를 나타낼 수 !=있습니다.
Mateen Ulhaq

4

"보다 작음"을 사용하는 것은 (보통) 의미 론적으로 정확합니다. 실제로 i10보다 작을 때까지 카운트 업을 의미 하므로 "보다 작음"은 의도를 명확하게 전달합니다. "같지 않음"을 사용하는 것은 사실상 콜 케이스에서 작동하지만 약간 다른 의미를 전달합니다. 어떤 경우에는 이것이 당신이 필요로 할 수도 있지만 내 경험상 이것은 결코 그렇지 않았습니다. 실제로 i10보다 크거나 작을 수 있지만 10이 될 때까지 계속 반복하려는 경우 해당 코드는 실제로 명확하게 주석이 필요하며 다른 구문으로 작성하는 것이 좋습니다. A와 while아마도 루프.


2

내가 less than오버를 선호하는 한 가지 이유 not equals는 경비원 역할을하는 것입니다. 일부 제한된 상황 (나쁜 프로그래밍 또는 위생 처리)에서는 not equals건너 뛸 수 있지만 less than여전히 유효합니다.

다음은 위생 검사가 부족하여 이상한 결과를 가져온 예입니다. http://www.michaeleisen.org/blog/?p=358


0

다음 <보다 사용을 선호하는 이유는 다음과 같습니다 !=. 전역 변수 범위가있는 언어를 사용하는 경우 다른 코드가 수정되면 어떻게됩니까 i? <대신 에 사용 하는 경우 !=최악의 경우 반복이 더 빨리 완료 i됩니다. 우연히 다른 코드가 증가 하고 for 루프에서 몇 번의 반복을 건너 뜁니다. 그러나 0에서 10까지 반복하고 루프가 9가되고 i이상한 이유로 쓰레드가 잘못 증가하면 어떻게됩니까 ? 그런 다음 루프는 반복을 마치고 i값이 이제 11이되도록 증가 합니다. 루프가 종료 조건을 건너 뛰지 i않았으므로 (10과 같지 않음) 이제 무한 루프됩니다.

반드시 이것을 일으키는 이상한 스레딩 및 전역 변수 유형 논리 일 필요는 없습니다. 역 추적해야하는 루프를 작성하는 것일 수도 있습니다. i루프 내부 를 뮤팅 하고 로직을 망치면 로직이 상한을 갖지 않고 !=무한 루프에 빠질 가능성이 적습니다.


3
물론 이것은 for-each 루프에 대한 완벽한 논증과 일반적인 기능적 프로그래밍 스타일처럼 보입니다. 그러나 가변 변수가 훨씬 더 재미 있을 때 왜 그렇게하고 싶 습니까?!
Tom Morris

3
나는 그것이 굉장히 좋은 이유라고 생각하지 않습니다. 어느 쪽이든 버그를 찾아서 수정해야하지만 무한 루프는 버그를 명백하게하는 경향이 있습니다.
ak2

0

임베디드 환경, 특히 시끄러운 환경에서는 RAM이 제대로 작동하는 것을 기대할 수 없습니다. '=='또는 '! ='를 사용하여 비교하는 조건부 (for, while, if)에서 항상 루프를 종료하는 중요한 값을 변수가 건너 뛸 위험이 있습니다. 이로 인해 위험한 결과가 발생할 수 있습니다-Mars Lander 수준의 결과. 조건에서 '<'또는 '>'를 사용하면 '알 수없는 미지의 물질'을 포착 할 수있는 추가적인 안전 수준이 제공됩니다.

원래 예에서, i설명 할 수 없을 정도로 10보다 큰 값으로 캐패 터링 된 경우 '<'비교는 오류를 즉시 포착하고 루프를 종료하지만 '! ='는 i0을 지나서 다시 감싸 질 때까지 계속 카운트됩니다. ~ 10.


2
for (i=4; i<length; i++) csum+=dat[i];합법적 인 패킷이 항상 length최소 4 개를 가지지 만 손상된 패킷이 수신 될 수 있는 코드와 관련하여 다른 관련 변형이 존재 합니다. 다른 패킷 유형의 길이 요구 사항이 다른 경우 각 패킷 유형마다 다른 처리의 일부로 길이의 유효성을 검사하지만 공통 논리의 일부로 체크섬의 유효성을 먼저 검사 할 수 있습니다. 길이가 짧은 패킷이 수신되면, 체크섬 계산이 "양호"또는 "불량"으로보고되는지는 중요하지 않지만 충돌하지 않아야합니다.
supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.