태그 보관물: loops

loops

스위치 내부에서 루프를 해제하는 방법은 무엇입니까? … more stuff …

다음과 같은 코드를 작성하고 있습니다.

while(true) {
    switch(msg->state) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
        break; // **HERE, I want to break out of the loop itself**
    }
}

그렇게하는 직접적인 방법이 있습니까?

플래그를 사용할 수 있고 스위치 바로 뒤에 조건부 중단을 두어 루프에서 벗어날 수 있다는 것을 알고 있습니다. C ++에 이미 이것에 대한 구조가 있는지 알고 싶습니다.



답변

전제

다음 코드는 언어 나 원하는 기능에 관계없이 잘못된 형식으로 간주되어야합니다.

while( true ) {
}

찬반론

while( true )루프는 열악한 형태이다 :

  • while 루프의 묵시적 계약을 끊습니다.
    • while 루프 선언은 유일한 종료 조건을 명시 적으로 명시해야 합니다.
  • 영원히 반복된다는 것을 의미합니다.
    • 종료 절을 이해하려면 루프 내의 코드를 읽어야합니다.
    • 영원히 반복되는 루프는 사용자가 프로그램 내에서 프로그램을 종료하는 것을 방지합니다.
  • 비효율적입니다.
    • “true”확인을 포함하여 여러 루프 종료 조건이 있습니다.
  • 버그가 발생하기 쉽습니다.
    • 각 반복마다 항상 실행되는 코드를 어디에 넣을지 쉽게 결정할 수 없습니다.
  • 불필요하게 복잡한 코드로 이어집니다.
  • 자동 소스 코드 분석.
    • 버그, 프로그램 복잡성 분석, 보안 검사를 찾거나 코드 실행없이 다른 소스 코드 동작을 자동으로 도출하기 위해 초기 차단 조건을 지정하면 알고리즘이 유용한 불변성을 결정하여 자동 소스 코드 분석 메트릭을 개선 할 수 있습니다.
  • 무한 루프.
    • 모든 사람이 항상 while(true)무한이 아닌 for 루프를 사용 하는 경우 루프에 실제로 종료 조건이 없을 때 간결하게 통신 할 수있는 기능을 잃게됩니다. (아마도 이것은 이미 일어 났으므로 요점은 논쟁의 여지가 있습니다.)

“이동”의 대안

다음 코드가 더 나은 형식입니다.

while( isValidState() ) {
  execute();
}

bool isValidState() {
  return msg->state != DONE;
}

장점

플래그가 없습니다. 아니 goto. 예외 없음. 변경하기 쉽습니다. 읽기 쉬운. 쉽게 고칠 수 있습니다. 추가로 코드 :

  1. 루프 자체에서 루프의 워크로드에 대한 지식을 분리합니다.
  2. 코드를 유지하는 누군가가 기능을 쉽게 확장 할 수 있습니다.
  3. 여러 종료 조건을 한 곳에서 할당 할 수 있습니다.
  4. 실행할 코드에서 종료 절을 분리합니다.
  5. 원자력 발전소에 더 안전합니다. 😉

두 번째 요점이 중요합니다. 코드가 어떻게 작동하는지 모르는 상태에서 누군가가 나에게 메인 루프가 다른 스레드 (또는 프로세스)에 CPU 시간을 허용하도록 요청하면 두 가지 솔루션이 떠 오릅니다.

옵션 1

일시 중지를 쉽게 삽입하십시오.

while( isValidState() ) {
  execute();
  sleep();
}

옵션 # 2

실행 무시 :

void execute() {
  super->execute();
  sleep();
}

이 코드는 포함 된 루프보다 더 간단합니다 (따라서 읽기 쉽습니다) switch. 이 isValidState메서드는 루프가 계속되어야하는지 여부 만 결정해야합니다. 이 방법의 주력이로 추상화한다 execute서브 클래스가 기본 동작을 재정의 할 수 있습니다 방법, (어려운 작업은 임베디드를 사용 switch하고 goto).

Python 예

StackOverflow에 게시 된 다음 답변 (Python 질문에 대한)을 대조하십시오.

  1. 영원히 반복하십시오.
  2. 사용자에게 선택 사항을 입력하도록 요청합니다.
  3. 사용자 입력이 ‘다시 시작’이면 계속 반복됩니다.
  4. 그렇지 않으면 루프를 영원히 중지하십시오.
  5. 종료.

암호

while True:
    choice = raw_input('What do you want? ')

    if choice == 'restart':
        continue
    else:
        break

print 'Break!' 

대:

  1. 사용자의 선택을 초기화하십시오.
  2. 사용자의 선택이 ‘다시 시작’이라는 단어 인 동안 반복합니다.
  3. 사용자에게 선택 사항을 입력하도록 요청합니다.
  4. 종료.

암호

choice = 'restart';

while choice == 'restart':
    choice = raw_input('What do you want? ')

print 'Break!'

여기 while True에서 오해의 소지가 있고 지나치게 복잡한 코드가 생성됩니다.


답변

사용할 수 있습니다 goto.

while ( ... ) {
   switch( ... ) {
     case ...:
         goto exit_loop;

   }
}
exit_loop: ;


답변

다른 해결책은 키워드 continue를와 함께 사용하는 것입니다 break.

for (;;) {
    switch(msg->state) {
    case MSGTYPE
        // code
        continue; // continue with loop
    case DONE:
        break;
    }
    break;
}

continue문을 사용하여 루프를 계속할 각 케이스 레이블을 완료 하고 문을 사용하여 루프를 break종료해야하는 케이스 레이블을 완료하십시오.

물론이 솔루션은 switch 문 다음에 실행할 추가 코드가없는 경우에만 작동합니다.


답변

이를위한 깔끔한 방법은 이것을 함수에 넣는 것입니다 :

int yourfunc() {

    while(true) {

        switch(msg->state) {
        case MSGTYPE: // ... 
            break;
        // ... more stuff ...
        case DONE:
            return;
        }

    }
}

선택적으로 (그러나 ‘나쁜 사례’) : 이미 제안했듯이 goto를 사용하거나 스위치 내부에서 예외를 throw 할 수 있습니다.


답변

AFAIK C ++에는 “이중 브레이크”또는 이와 유사한 구조가 없습니다. 가장 가까운 것은 goto-이름에 나쁜 의미가 있지만 이유 때문에 언어에 존재합니다-신중하고 드물게 사용되는 한 실행 가능한 옵션입니다.


답변

스위치를 다음과 같이 별도의 기능에 넣을 수 있습니다.

bool myswitchfunction()
{
    switch(msg->state) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
        return false; // **HERE, I want to break out of the loop itself**
    }
    return true;
}

while(myswitchfunction())
    ;


답변

goto를 좋아하지 않더라도 루프를 종료하기 위해 예외를 사용하지 마십시오. 다음 샘플은 얼마나 추한지 보여줍니다.

try {
  while ( ... ) {
    switch( ... ) {
      case ...:
        throw 777; // I'm afraid of goto
     }
  }
}
catch ( int )
{
}

답변 goto에서와 같이 사용 합니다. 이 경우 다른 옵션보다 코드가 더 명확 해집니다. 질문이 도움 되기를 바랍니다 .goto

그러나 나는 goto문자열 때문에 사용하는 것이 유일한 옵션 이라고 생각 합니다 while(true). 루프 리팩토링을 고려해야합니다. 다음 솔루션을 가정합니다.

bool end_loop = false;
while ( !end_loop ) {
    switch( msg->state ) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
        end_loop = true; break;
    }
}

또는 다음과 같은 경우도 있습니다.

while ( msg->state != DONE ) {
    switch( msg->state ) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
}