'for'루프에서 1 씩 증가 할 때! = 대신> (<)를 사용해야하는 기술적 이유가 있습니까?


198

나는 for이런 루프를 거의 보지 못했다 .

for (int i = 0; 5 != i; ++i)
{}

루프 에서 1 씩 증가 할 때 >또는 <대신 사용해야하는 기술적 이유가 있습니까? 아니면 이것은 관습에 더 가깝습니까?!=for


104
당신이 이제까지 변경하면 그것은 더 쉽게 읽을 플러스 i++i+=2(예를 들어),이 (영원히 가능성 또는) 아주 긴 시간 동안 실행됩니다. 이제 일반적으로 <반복자를 1 이상< 증가시키는 경우에 사용 하므로 일관성을 위해 반복자를 1 씩 증가시키는 경우 에도 사용할 수 있습니다 .
barak manos

112
5 != i은 악마
Slava

27
당신은 항상 당신이하고있는 일을 의식해야하지만 어쨌든 실수를 할 것입니다. <를 사용하면 누군가이 코드에 버그를 도입 할 가능성이 줄어 듭니다.
Aurast

40
@OleTange 부동 소수점 숫자를 사용하여 반복하는 경우 이미 고정되어 있습니다.
CaptainCodeman

29
@Slava ... 악하지 않다. if ( i == 5 ) ...와 사이의 차이를 만드는 간단한 오타로 C에서 결코 친척이 없었습니다 if ( i = 5 ). 매우 다른 것들. 피연산자를 뒤집 으면 문제를 방지 할 수 있습니다. 리터럴이 lvals없기 때문에 할당 할 수없고 컴파일러가 오타를 던집니다. @Zingam : 좋은 방어 프로그래밍!
Nicholas Carey

답변:


303
while (time != 6:30pm) {
    Work();
}

오후 6시 31 분입니다 ... 젠장, 이제 집에 갈 다음 기회는 내일입니다! :)

이것은 더 강한 제한이 위험을 완화시키고 이해하기에 더 직관적임을 보여줍니다.


25
때로는 "위험 완화"를 시도하면 버그가 숨겨집니다. 루프의 디자인이 오후 6시 30 분에 눈에 띄지 않게 막아야한다면을 사용 <하면 버그가 숨겨 지지만을 사용 !=하면 문제가 있음을 알 수 있습니다.
Adrian McCarthy

27
@AdrianMcCarthy : 반드시 그런 것은 아닙니다. 진단을 더 어렵게 만드는 두 번째 버그가 발생할 수 있습니다 .
궤도에서 가벼움 경주

4
@AdrianMcCarthy : 그건 내 요점입니다. 당신은 당신이 아직 보지 못한 몇 가지 사례를 가질 수 있습니다.)
궤도에서 가벼움 경주

6
반복자는 @AdrianMcCarthy 포인트의 완벽한 예라고 생각합니다. 권장되는 비교는 <대신! =입니다.
Taekahn

5
나는이 오류를 정확히 보았습니다 (그리고 3 개월의 디버깅이 발생했습니다). 그러나이 답변은 완전히 요점을 놓칩니다. 주어진 예 에서 종료 조건을 놓치는 것은 불가능 합니다. 당신은 의식적으로! =보다 <를 선택하는 것이이 사실을 강력하게 주장하는 것이라고 말할 수 있습니다. 존재하지 않는 위험을 완화하는 것은 코드 냄새입니다. (<는 관용적이라고 주장 할 수있다. <는 관용적이며, 다른 어떤 방법으로나 사용하는 것이 좋다.)
Ian Goldby

95

기술적 이유는 없습니다. 그러나 위험, 유지 관리 성 및 코드에 대한 이해가 완화됩니다.

< 또는 >!= 대부분의 경우에 동일한 목적을 달성하는 것보다 더 강한 제한이 있으며 (모든 실제적인 경우에도 말하고 있습니다).

여기에 중복 된 질문이 있습니다 . 그리고 하나의 흥미로운 답변 입니다.


6
반복자와 같이 <또는>를 지원하지 않지만 == 및! =를 지원하는 일부 유형이 있습니다.
Simon B

1
int 의 for 루프입니다 . 반복자가 없습니다.
Ely

7
"그러나 위험, 유지 보수성 및 코드에 대한 이해도 완화가 있습니다." 모든 것은 적절하게 기술적 인 이유입니다. :-)
TJ Crowder

@TJCrowder 머신이 결과적으로 무엇을하는지 이야기하고 싶을 때 어떤 유형의 이유가 있습니까?
Brilliand

1
@ DanSheppard 저는 일반적으로 위험 및 유지 관리 가능성의 완화를 사업상의 이유로 생각하고 코드에 대한 이해가 사회적 이유 인 것으로 간주합니다 (이러한 이유는 모두 기술적 문제에 적용됨). "위험 완화"고려 사항은 기술적 인 문제로 제한되지 않으며, 다른 사람과 함께 작업하는 경우 (관련 기계가 전혀 변경되지 않은 경우에도) "코드 이해 이해"고려 사항이 변경 될 수 있습니다. ).
Brilliand

85

네 이유가 있습니다. 이런 식으로 for 루프를 작성하면 (일반 인덱스 기반)

for (int i = a; i < b; ++i){}

그런 다음 a및의 모든 값에 대해 예상대로 작동합니다 b(예 : a > b무한대 대신에 0 반복 을 사용한 경우i == b; ).

반면에 반복자에 대해서는 다음과 같이 작성하십시오.

for (auto it = begin; it != end; ++it) 

모든 반복자가을 구현해야 operator!=하지만 모든 반복자에 대해 그런 것은 아닙니다.operator< .

범위 기반 for 루프

for (auto e : v)

공상 설탕뿐만 아니라 잘못된 코드를 작성할 가능성을 상당히 줄입니다.


4
좋은 예입니다. !=대신의 경우에 관심 이 <있습니다. 나는 개인적으로 생각한 적이 없다.
Ely

@Elyasin 나는 좋은 것을 찾지 못했고 나쁜 것을 게시하고 싶지 않았다 : 어떤 종류의 원형 컨테이너를 가지고 있다고 상상해보십시오. 여기서 컨테이너 N의 크기를 + x 모듈로 증가시키고 루프를 멈추고 싶을 때 특정 인덱스에 도달합니다 .... 그건 정말 나쁜 예입니다. 어쩌면 더 좋은 것을 발견 할 것입니다
idclev 463035818

<대신! =를 사용하는 동일한 루프는이 컨텍스트에서 <(또는>)의 장점이 무엇인지 명확하게합니다. for (int i=a; i != b; i++) {}
Paul Smith

10
!=이터레이터 외에 다른 것을 사용하는 것은 매우 위험합니다. 때로는 이터레이터를 비교하는 것보다 적을 수 있지만 (예를 들어 포인터 임) 비교는 의미가 없습니다 (링크 된 목록입니다).
Zan Lynx

1
공백을 진지하게 사용하는 법을 배우십시오.
Miles Rout

70

당신은 같은 것을 가질 수 있습니다

for(int i = 0; i<5; ++i){
    ...
    if(...) i++;
    ...
}

내부 변수로 루프 변수를 작성하면 i!=5해당 루프가 중단되지 않을 수 있습니다. 불평등을 확인하는 것이 더 안전합니다.

가독성에 대한 편집 . 불평등 형태가 더 자주 사용됩니다. 따라서 이해해야 할 것이 없기 때문에 읽기 속도가 매우 빠릅니다 (작업이 일반적이므로 브레인로드가 줄어 듭니다). 따라서 독자가 이러한 습관을 활용하는 것이 좋습니다.


6
이 유형의 내부 "if (조건) 그리고 i ++"는 내가 생각한 첫 번째 것입니다.
WernerCD

3
이것이 가장 높은 투표 응답이 될 것으로 기대했습니다. 나는 그것을 찾기 위해 이것을 멀리 스크롤해야한다는 것에 놀랐다. 이것은 "글쎄, 당신은 가장 강한 조건을 사용해야한다"보다 초보자 프로그래머를 설득시키는 데 훨씬 더 많은 일을한다. 다른 답변은 위에 머물러 있으면 OP의 제안 코드에서 무엇이 잘못 될 수 있는지에 대한 명확하고 명백한 설명으로 통합해야합니다.
msouth

1
@msouth 나는 완전히 동의하지만 내 POV는 매우 주관적입니다.)
johan d

3
@msouth 예기치 않은 프로덕션 동작으로 인해 버그가 발생하면 마음에 들지 않습니까? :-)
deworde

3
@msouth 봐, 우리가해야 할 일은 결코 실수하지 않고 모든 것이 잘 될 것입니다. 단순함.
deworde

48

마지막으로 이것을 방어 프로그래밍 이라고 합니다 합니다. 이는 프로그램에 영향을 미치는 현재 및 미래의 오류를 피하기 위해 항상 가장 강력한 사례를 취하는 것을 의미합니다.

방어 프로그래밍이 필요하지 않은 유일한 경우는 상태가 사전 및 사후 조건에 의해 입증 된 경우입니다 (그러나 이것이 모든 프로그래밍 중 가장 방어적임을 증명).


2
이를 지원하는 좋은 예는 다음과 같습니다. 메모리는 방사선으로 인한 비트 플립 ( SEU )에 취약합니다 . 조건을 int위해를 사용할 때 i != 15, 특히 sizeof(int)64 비트 인 기계에서 4 번째 비트 이상을 뒤집 으면 카운터가 장시간 작동합니다. 또는 메모리가 너무 많기 때문에 대형 슈퍼 컴퓨터에서 사용할 수 있습니다.
Josh Sanford

2
방사선이 기억을 바꿀 때 프로그램이 제대로 작동한다고 생각하는 것은 낙관적이며 치명적인 사고 방식입니다. :)
Luis Colorado

37

나는 같은 표현이

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

보다 의도를표현한다

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

전자는 조건이 범위에 대한 독점 상한에 대한 테스트임을 분명히 지적합니다. 후자는 종료 조건의 이진 테스트입니다. 그리고 루프의 본문이 사소한 것이 아니라면, 인덱스 for자체 가 명령문 에서만 수정 된 것은 분명하지 않을 수 있습니다.


13
"이 루프를 최대 5 회 실행하고 싶습니다"대 "필요하지 않은 정확한 5 회를 제외하고 필요한 횟수만큼이 루프를 실행하고 싶습니다."
주교

범위의 상한을 언급하면 ​​+1입니다. 나는 이것이 숫자 범위에 중요하다고 생각합니다. ! = 다음과 같은 for 루프에서 적절한 범위를 정의하지 않습니다
element11

22

반복자는 !=표기법 을 가장 자주 사용할 때 중요한 경우입니다 .

for(auto it = vector.begin(); it != vector.end(); ++it) {
 // do stuff
}

부여 : 실제로는 range-for:에 의존하는 동일한 내용을 작성합니다 .

for(auto & item : vector) {
 // do stuff
}

하지만 요점은 남아있다 : 하나는 일반적으로 사용하는 반복자를 비교 ==하거나 !=.


2
이터레이터는 종종 평등 / 불평등의 개념만을 가지고 순서를 가지지 않기 때문에 !=그것을 사용 합니다. 예를 들어,에 std::vector당신은 할 수 사용 <반복자의 인덱스 / 포인터에 연결 한, 그러나에 std::set이 이진 트리를 산책으로, 더 엄격한 순서가 없다.
Martin C.

19

루프 조건은 강제 루프 불변입니다.

루프의 본문을 보지 않는다고 가정하십시오.

for (int i = 0; i != 5; ++i)
{
  // ?
}

이 경우 루프 반복이 시작될 때 i같지 않은 것을 알 수 5있습니다.

for (int i = 0; i < 5; ++i)
{
  // ?
}

이 경우 루프 반복 시작시 i보다 작은 것을 알 수 5있습니다.

두 번째는 첫 번째보다 훨씬 더 많은 정보입니다. 이제 프로그래머의 의도는 (거의 확실합니다) 동일하지만 버그를 찾고 있다면 코드 줄을 읽는 것에 대한 확신을 갖는 것이 좋습니다. 그리고 두 번째 불변성을 강제 합니다. 이는 첫 번째 경우에 물린 버그가 두 번째 경우에는 발생할 수 없거나 메모리 손상을 유발하지 않습니다.

with <보다 적은 코드를 읽음으로써 프로그램의 상태에 대해 더 많이 알고 있습니다 !=. 최신 CPU에서는 차이가없는 것과 동일한 시간이 걸립니다.

당신이 경우 i루프 본문에서 조작,하지 않은 항상 1 씩 증가했다, 그리고 그것은보다 적은 시작5 , 차이가 없을 것이다. 그러나 그것이 조작되었는지 알기 위해서는 이러한 각 사실을 확인해야합니다.

이러한 사실 중 일부는 비교적 쉽지만 잘못 될 수 있습니다. 그러나 루프 전체를 점검하는 것은 고통입니다.

C ++에서는 다음 indexes과 같은 유형을 작성할 수 있습니다 .

for( const int i : indexes(0, 5) )
{
  // ?
}

위의 두 for루프 중 하나와 동일한 작업 을 수행하며 컴파일러까지 동일한 코드로 최적화합니다. 그러나 여기, 당신은 알고i가 선언되는 한, 루프의 본문에 조작 할 수없는 const코드 손상 메모리없이.

컨텍스트를 이해하지 않고 코드 라인에서 얻을 수있는 정보가 많을수록 문제를 쉽게 추적 할 수 있습니다. <정수 루프의 경우 해당 줄의 코드 상태에 대한 정보를 제공합니다 !=.


13

예; OpenMP는 루프를 !=조건 과 병렬화하지 않습니다 .


13

변수 i가 큰 값으로 설정 되었을 수 있으며 !=연산자를 사용 하면 무한 루프로 끝납니다.


1
실제로 끝이없는 것은 아닙니다. 대부분의 C 구현 i에서 최대치에 자동으로 감쌀 것입니다. 그러나 네, 당신이 기다릴 준비가 된 것보다 더 길 것입니다.
usr2564301

12

다른 많은 답변에서 볼 수 있듯이! = 대신 <를 사용해야하는 이유가 있습니다.

솔직히, 나는 당신이 컨벤션의 중요성을 충분히 강조 할 수 있다고 생각하지 않습니다. 이 예제에서는 다른 프로그래머가 수행하려는 작업을 쉽게 알 수 있지만 두 번 수행 할 수 있습니다. 프로그래밍하는 동안 작업 중 하나는 모든 사람이 읽을 수 있고 친숙하게 만들 수 있기 때문에 누군가가 코드를 업데이트 / 변경해야 할 때 필연적으로 다른 코드 블록에서 수행중인 작업을 파악하는 데 많은 노력을 기울이지 않습니다. . 누군가가을 사용하는 것을 보았을 때 !=, 그들이 대신 사용하는 이유가 있다고 가정 <했을 것입니다. 큰 루프 인 경우 필요한 것을 만든 것을 알아 내려고하는 모든 것을 살펴볼 것입니다 ... 낭비 된 시간.


12

Ian Newson이 이미 말했듯이 부동 변수를 안정적으로 반복하고로 종료 할 수는 없습니다 !=. 예를 들어

for (double x=0; x!=1; x+=0.1) {}

0.1은 부동 소수점으로 정확하게 표현 될 수 없으므로 카운터는 1을 잃어 버립니다 <.

(그러나 0.9999 ...를 마지막으로 받아 들여진 숫자로 가정하거나 (이는 가정을 위반 한 경우) 이미 1.0000000000000001에서 종료하는지 여부는 기본적으로 정의되지 않은 동작 입니다.)


10

나는 형용사 "기술적"을 사용하여 생성 된 코드의 성능과 같은 언어 행동 / 질투 및 컴파일러 부작용을 의미합니다.

이를위한 대답은 no (*)입니다. (*)는 "프로세서 설명서를 참조하십시오". 일부 첨단 RISC 또는 FPGA 시스템으로 작업하는 경우 생성되는 명령어와 비용을 확인해야합니다. 당신은 거의 모든 기존의 현대 건축을 사용하는 경우, 그때가 사이의 비용 유의 프로세서 수준의 차이는 없다 lt, eq, negt.

경우 당신이 가장자리 케이스를 사용하는 당신은 찾을 수있는 !=세 가지 작업 (요구 cmp, not, beq(두 대)를 cmp,blt xtr myo ). 이 경우에도 RTM입니다.

대부분의 경우, 특히 포인터 나 복잡한 루프로 작업 할 때 방어 / 경화가 발생합니다. 치다

// highly contrived example
size_t count_chars(char c, const char* str, size_t len) {
    size_t count = 0;
    bool quoted = false;
    const char* p = str;
    while (p != str + len) {
        if (*p == '"') {
            quote = !quote;
            ++p;
        }
        if (*(p++) == c && !quoted)
            ++count;
    }
    return count;
}

덜 귀중한 예는 반환 값을 사용하여 증분을 수행하고 사용자의 데이터를 수락하는 경우입니다.

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i != len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;

        std::cin >> step;
        i += step; // here for emphasis, it could go in the for(;;)
    }
}

이것을 시도하고 값 1, 2, 10, 999를 입력하십시오.

이것을 막을 수 있습니다 :

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i != len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;
        std::cin >> step;
        if (step + i > len)
            std::cout << "too much.\n";
        else
            i += step;
    }
}

그러나 아마도 당신이 원했던 것은

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i < len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;
        std::cin >> step;
        i += step;
    }
}

이 향해 컨벤션 바이어스의 무언가는 또한 <표준 컨테이너의 순서는 종종에 의존하기 때문에, operator<여러 STL 컨테이너에 인스턴스 해싱을 위해, 말함으로써 평등을 결정한다

if (lhs < rhs) // T.operator <
    lessthan
else if (rhs < lhs) // T.operator < again
    greaterthan
else
    equal

만약 lhsrhs사용자 정의 클래스는이 코드 등을 작성하는

if (lhs < rhs) // requires T.operator<
    lessthan
else if (lhs > rhs) // requires T.operator>
    greaterthan
else
    equal

구현자는 두 가지 비교 기능을 제공해야합니다. 따라서 <선호하는 운영자가되었습니다.


가독성을 위해 제어 부분에 i + = 단계가 있어야합니다. 만약 당신이 단계 = 0에 것
Mikkel Christiansen

1
이것이 좋은 코드의 가독성에 도움이
되겠지만

9

모든 종류의 코드를 작성하는 방법은 여러 가지가 있으며 (보통)이 경우에는 두 가지 방법이 있습니다 (<= 및> =를 세면 세 가지).

이 경우 사람들은>와 <을 선호하여 루프에서 예기치 않은 일이 발생하더라도 (버그처럼) 무한 반복 (BAD)하지 않도록합니다. 예를 들어 다음 코드를 고려하십시오.

for (int i = 1; i != 3; i++) {
    //More Code
    i = 5; //OOPS! MISTAKE!
    //More Code
}

(i <3)을 사용하면 더 큰 제한을두기 때문에 무한 루프로부터 안전합니다.

프로그램의 실수로 모든 것을 종료하거나 버그로 계속 작동하는지 여부는 실제로 선택합니다.

이것이 도움이 되었기를 바랍니다!


하나는 무한 루프가 실수의 좋은 지표라고 주장 할 수 있지만, 다른 하나는 i = 5가 반드시 실수는 아니라고 주장 할 수 있습니다.
njzk2

7

가장 일반적인 이유 < 는 규칙입니다. 더 많은 프로그래머들은 "인덱스가 끝날 때까지"가 아니라 "인덱스가 범위 내에있는 동안"이와 같은 루프를 생각합니다. 당신이 할 수있는 가치는 관습에 충실합니다.

다른 한편으로, 여기에 많은 답변은 <양식 을 사용하면 버그를 피하는 데 도움 이된다고 주장합니다 . 많은 경우 이것이 버그를 숨기는 데 도움이된다고 주장합니다 . 루프 인덱스가 최종 값에 도달해야하고 실제로 그 값을 초과하면 오작동 (또는 다른 버그의 부작용)을 유발할 수있는 예상치 못한 일이 발생합니다. 는 <가능성이 버그의 발견을 지연됩니다. 는 !=당신이 빨리 버그를 발견하는 데 도움이되는 매점, 중단, 또는 충돌로 이어질 가능성이 높습니다. 버그가 빨리 발견 될수록 더 저렴하게 해결할 수 있습니다.

이 규칙은 배열 및 벡터 인덱싱에 고유합니다. 거의 모든 다른 유형의 데이터 구조를 탐색 할 때는 반복자 (또는 포인터)를 사용하고 종료 값을 직접 확인해야합니다. 이러한 경우 반복자가 실제 최종 값에 도달하고이를 초과하지 않도록해야합니다.

예를 들어, 일반 C 문자열을 단계별로 실행하는 경우 일반적으로 다음과 같이 작성하는 것이 더 일반적입니다.

for (char *p = foo; *p != '\0'; ++p) {
  // do something with *p
}

...보다

int length = strlen(foo);
for (int i = 0; i < length; ++i) {
  // do something with foo[i]
}

우선, 문자열이 매우 길면 두 번째 형식이 strlen문자열을 통과하는 다른 형식이기 때문에 속도가 느려집니다 .

C ++ std :: string을 사용하면 길이를 쉽게 사용할 수 있어도 범위 기반 for 루프, 표준 알고리즘 또는 반복자를 사용합니다. 반복자를 사용 !=하는 경우 다음 <과 같이 규칙 대신 을 사용하는 것이 좋습니다 .

for (auto it = foo.begin(); it != foo.end(); ++it) { ... }

마찬가지로 트리 나 목록 또는 deque를 반복하면 일반적으로 인덱스가 범위 내에 있는지 확인하는 대신 null 포인터 나 다른 센티넬을 감시해야합니다.


3
프로그래밍에서 관용구의 중요성을 강조하는 것이 옳습니다. 일부 코드를 보면 친숙한 패턴이 있으면 패턴을 유추하는 데 시간을 낭비 할 필요가 없지만 코드의 핵심으로 바로 이동할 수 있습니다. 나는 그것이 요다 비교의 주된 그립이라고 생각합니다.
Toby Speight

7

이 구문을 사용하지 않는 한 가지 이유는 부동 소수점 숫자입니다. !=숫자가 동일하게 보이더라도 거의 참으로 평가되지 않으므로 float와 함께 사용하는 것은 매우 위험한 비교입니다. <또는 >이 위험을 제거합니다.


루프 반복자가 부동 소수점 숫자이면 !=vs <가 가장 적은 문제입니다.
Lundin

7

이 연습을 따르는 데는 두 가지 관련 이유가 있습니다. 프로그래밍 언어는 결국 사람이 읽을 수있는 언어라는 사실과 관련이 있습니다.

(1) 약간의 중복성. 자연어에서는 일반적으로 오류 수정 코드와 매우 유사하게 필요한 것보다 더 많은 정보를 제공합니다. 여기에 추가 정보는 루프 변수입니다 i(여기에서 중복성을 어떻게 사용했는지 참조하십시오. '루프 변수'의 의미를 모르거나 변수 이름을 잊어 버린 경우 "루프 변수 i"를 읽은 후 5)와 다르지 않고 루프 동안 정보가 5보다 작습니다. 중복성은 가독성을 향상시킵니다.

(2) 협약. 언어에는 특정 상황을 표현하는 특정 표준 방법이 있습니다. 당신이 어떤 말을하는 기존의 방식을 따르지 않는다면, 당신은 여전히 ​​이해 될 것이지만, 특정 최적화가 작동하지 않기 때문에 메시지를받는 사람을위한 노력은 더 커집니다. 예:

핫 매쉬에 대해 이야기하지 마십시오. 어려움을 밝히십시오!

첫 번째 문장은 독일 관용구의 문자 번역입니다. 두 번째는 일반적인 영어 관용구이며 주요 단어가 동의어로 대체되었습니다. 결과는 이해할 수 있지만 이것보다 이해하는 데 많은 시간이 걸립니다.

덤불을 두드리지 마십시오. 문제를 설명해주세요!

첫 번째 버전에서 사용 된 동의어가 영어 관용구의 기존 단어보다 상황에 더 잘 맞는 경우에도 마찬가지입니다. 프로그래머가 코드를 읽을 때 비슷한 힘이 적용됩니다. 이 이유도 5 != i하고 5 > i퍼팅의 이상한 방법입니다 하지 않는 한 당신이 더 정상적인 교환 표준 인 환경에서 작업 i != 5하고 i < 5이런 식으로는. 일관성이 5 == i자연 스럽지만 오류가 발생하기 쉬운 쓰기 보다는 기억하기 쉽기 때문에 그러한 방언 커뮤니티가 존재합니다 i == 5.


1
아우 지제 이치 넷 . 마찬가지로 테스트를 작성하지 않을 것입니다 i < 17+(36/-3)(이것이 다른 곳에서 사용되는 상수 일지라도 명확성을 위해 이름 을 작성해야합니다 !).
usr2564301

6

이러한 경우 관계 비교를 사용하는 것이 다른 무엇보다 인기있는 습관입니다. 그것은 반복자 범주와 같은 개념적 고려 사항과 그 비교 가능성이 우선 순위로 고려되지 않은 시대에 인기를 얻었습니다.

평등 비교는 비교되는 값에 대한 요구 사항이 적기 때문에 가능하면 관계 비교 대신 평등 비교를 사용하는 것이 좋습니다. 존재 EqualityComparable로는 것보다 낮은 요구 사항입니다 LessThanComparable을 .

이러한 맥락에서 평등 비교의 더 넓은 적용 가능성을 보여주는 또 다른 예는 unsigned반복을 아래로 구현하는 인기있는 수수께끼입니다 0. 다음과 같이 할 수 있습니다

for (unsigned i = 42; i != -1; --i)
  ...

위의 내용은 부호있는 반복과 부호없는 반복 모두에 동일하게 적용되는 반면 관계형 버전은 부호없는 유형으로 분류됩니다.


2

루프 변수가 (의도적이지 않은) 차체 내부에서 변경되는 예제 외에도 작거나 큰 연산자를 사용하는 다른 방법이 있습니다.

  • 부정은 코드를 이해하기 어렵게 만듭니다
  • <또는 >하나의 문자이지만 !=두 개

4
두 번째 총알은 기이 한 이유입니다. 코드는 정확하고 명확해야합니다. 컴팩트는 훨씬 덜 중요합니다.
Jonathan Leffler

@JonathanLeffler 글쎄, TDD REPL에서, 그 여분의 문자는 파싱에 1 나노 초이며, 쓰기로 인한 버그를 찾기 위해 10 억 번 반복하여 5 != $i내 인생의 1 초가 걸렸습니다. 어 ... snicker
주교

1

위험을 완화한다고 언급 한 다양한 사람들 외에도 다양한 표준 라이브러리 구성 요소와 상호 작용하는 데 필요한 기능 과부하 수를 줄입니다. 예를 들어, 형식을에 저장 std::set하거나 키로 std::map사용하거나 일부 검색 및 정렬 알고리즘과 함께 사용 std::less하려는 경우 표준 라이브러리는 일반적 으로 대부분의 알고리즘이 엄격한 약한 순서 만 필요하므로 개체를 비교하는 데 사용 합니다 . 따라서 비교 (물론 의미가있는 경우) <대신 비교 를 사용하는 것이 좋습니다 !=.


1
오버로드 수에는 맞을 수도 있지만 객체의 요구 사항을 고려할 때 거의 모든 객체에 대해 !=연산자를 정의 할 수 있지만 엄격한 약한 순서를 정의하는 것이 항상 가능한 것은 아닙니다. 이러한 의미 !=에서 유형에 대한 요구 사항이 적기 때문에 더 좋습니다. 그러나 나는 여전히 <.
idclev 463035818

0

구문 관점에서 문제는 없지만 그 표현의 논리 5!=i는 건전하지 않습니다.

내 의견 !=으로는 for 루프의 경계를 설정하는 데 사용 하는 것이 논리적으로 건전하지 않습니다 .for 루프는 반복 색인을 늘리거나 줄이므로 반복 색인이 경계를 벗어날 때까지 루프를 반복하도록 설정하십시오 (!= 것은 아닙니다. 적절한 구현.

그것은 작동하지만 사용할 때 경계 데이터 처리가 손실되기 때문에 그것이 잘못된 행동하는 경향이 !=증가 문제에 대한 (당신은 처음부터 알고 있다는 것을 의미 경우 증가하거나 감소) 대신 이유, !=(가) <>>==>사용됩니다.


2
논리는 완벽합니다. 루프 i는 언제 5종료됩니다. 다른 말을 하시겠습니까?
Dan Getz

1
열로 인해 데이터가 올바르게 전송되지 않으면 electro.magnetic이 코드 실행에 영향을 미칩니다. ECC RAM이있는 일반 워크 스테이션 또는 서버에서이 작업을 수행하면 문제가 없습니다 (논리적, 기술적 또는 물리적)
Markus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.