2011-05-03 7 views
8

게임을 끝낸 후에 다시 시작할 수있는 테트리스 게임을 만들었습니다. 나는 이것을 goto (코드 참조)로 신속하고 더러웠다. Game 클래스는 소멸자를 사용합니다. 이러한 goto가 호출됩니까? 이 고토는 얼마나 나쁜 것입니까, 받아 들일 수 있습니까? 아니면 내가 대신해야합니까?이 고토는 얼마나 나쁜가요?

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { 
    // initiate sdl 
    sdl_init(); 

    // seed rng 
    srand(time(NULL)); 

    newgame: // new game label 
    Game game(GAME_WIDTH, GAME_HEIGHT, 1, screen); 

    // keydowns 
    bool fastfall = false; 
    bool gamerunning = true; 
    Uint32 lastupdate = 0; 

    while (gamerunning && game.isalive()) { 
     // game running stuff here 
    } 

    // game over stuff here 

    while (gamerunning) { 
     if (SDL_PollEvent(&event)) { 
      if (event.type == SDL_QUIT) { 
       gamerunning = false; 
      } else if (event.type == SDL_KEYDOWN) { 
       if (event.key.keysym.sym == SDLK_r) goto newgame; // yay a new game! 
      } 
     } 
    } 

    TTF_Quit(); 
    SDL_Quit(); 
    return 0; 
} 
+4

ewww ... 그것은 단지 당신이 결과로 살 수있는 경우, 고토를 사용할 수 있습니다 물론 고토 –

+4

을 위해 인 경우 : http://xkcd.com/292/ – bitmask

답변

13

소멸자에 관한 질문에 답하려면 다른 누구도 다루지 않은 것 같습니다. 6.6/2에 따르면 소멸자 이라고합니다. 인용구 : 자동 저장 기간 (3.7.2) 모든 구성 객체 요구 범위에서

출구에

(단 달성), 소멸자 (12.4)된다 (명명 된 개체 또는 임시직)이다 해당 범위에서 선언 된 의 역순으로 해당 선언 블록 밖으로 루프 밖으로 이동하거나 다시 자동 저장 기간을 갖는 초기화 변수를지나 상기 로부터 전송 된 시점 범위에 자동 저장 기간이 변수 파괴를 수반하지만 포인트가로 이전되었습니다.

그러나이 경우에는 여전히 goto을 제안하지 않습니다. 분명히 (나에게 어쨌든) 무슨 일이 일어나고 있는지 알려주지는 않습니다. while 루프를 사용하여 조건을 대신 사용하도록해야합니다.

단순한 것조차도 더 분명해야합니다 (내부 브레이크없이 다시 작성하는 방법이 있긴하지만). 이 지역 주민들은이 같은 while 루프 내부에서 사용 정리되는 것을 완벽하게 명백하다 :

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { 
    // initiate sdl 
    sdl_init(); 

    // seed rng 
    srand(time(NULL)); 

    bool gamerunning = true; 
    while(gamerunning) 
    { 
     Game game(GAME_WIDTH, GAME_HEIGHT, 1, screen); 

     // keydowns 
     bool fastfall = false; 
     Uint32 lastupdate = 0; 

     while (gamerunning && game.isalive()) { 
      // game running stuff here 
     } 

     // game over stuff here 

     while (gamerunning) { 
      if (SDL_PollEvent(&event)) { 
       if (event.type == SDL_QUIT) { 
        gamerunning = false; 
       } else if (event.type == SDL_KEYDOWN) { 
        if (event.key.keysym.sym == SDLK_r) break; // yay a new game - get out of the "what to do next" loop. 
       } 
      } 
     } 
    } 

    TTF_Quit(); 
    SDL_Quit(); 
    return 0; 
} 
+3

소멸자 질문에 답하는 인용문 +1 (나는 완전히 놓칠 수 있었다. ..) –

16

당신은 쉽게 while 루프에서이 기능의 대부분을 가하고, 그것의 탈옥하는 플래그를 설정하여이를 방지 할 수있다.

C에서 goto의 실제 "수용 가능한"사용은 오류의 경우 일반적인 정리 코드로 점프하는 것입니다. C++에서는 이러한 예외조차도 피할 수 있습니다. 정말 변명의 여지가 없습니다!

+0

나는 알고있다. 그러나 이것은 정말로 적당하지 않다. 고토가 더 적절하다고 느낀다. 그래서이 고토가 받아 들여질 수 있는지 알고 싶습니다. – orlp

+1

@night : 왜 지저분한 'goto'보다 루프가 더 이상 보이지 않는 이유는 무엇입니까? 게임을 더 이상하고 싶지 않을 때까지 게임을 반복합니다. 그건 내게 자연스러운 것처럼 보입니다 ... –

+0

재시작은 코드 시작 부분으로 돌아가는 것으로 보입니다. 바로 이것이 바로 goto가하는 일입니다. – orlp

2

고토는 거의 사용하지 않는 것이 좋습니다. 이 예외는 많은 중첩 루프에서 빠르게 빠져 나와 메모리를 확보하고 종료해야하는 정리 작업 인 것으로 보입니다. 여기는 while 루프로 쉽게 대체 할 수 있습니다. 그대로두면 디버깅 및 유지 관리가 더 어려워집니다.

-1
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { 
    // initiate sdl 
    sdl_init(); 

    // seed rng 
    srand(time(NULL)); 


    while (1) { 
    Game game(GAME_WIDTH, GAME_HEIGHT, 1, screen); 

    // keydowns 
    bool fastfall = false; 
    bool gamerunning = true; 
    Uint32 lastupdate = 0; 

    while (gamerunning && game.isalive()) { 
     // game running stuff here 
    } 

    // game over stuff here 
    restart_game = false; 
    while (gamerunning) { 
     if (SDL_PollEvent(&event)) { 
      if (event.type == SDL_QUIT) { 
       gamerunning = false; 
      } else if (event.type == SDL_KEYDOWN) { 
       if (event.key.keysym.sym == SDLK_r) { 
         restart_game = true; break; 
       } 
      } 
     } 
    } 
    if (!restart_game) break; 
    } 

    TTF_Quit(); 
    SDL_Quit(); 
    return 0; 
} 
+0

이것은 더욱 심각합니다. 휴식, 계속 그리고 고토는 모두 같은 방식으로 "악"입니다. –

5

중요한 블록을 함수로 분리 한 다음 goto을 호출하는 대신 함수를 호출하십시오.

6

goto 대신 newgame 태그의 모든 것을 함수의 while 루프 끝 부분에 넣을 수 있습니다. 이 함수의 반환 값은 다시 실행해야하는지 알려줍니다. 그래서 같은 것입니다 : 코드가 고토를 사용하는 경우 runGame() 당신이 당신의 게임 코드에서 사용하는 주요 기능에서 전달하는 매개 변수와 1을 반환 당신은 것

... 
srand(time(NULL)); 

while (runGame()) 
{ 
} 

TTF_Quit(); 
... 

및 마지막 게임 일 때 0입니다.

0

goto (예 : 상태 시스템 구현)을 사용하기에 좋은시기가 있지만 실제로는 그 중 하나인지는 잘 모르겠습니다.

나인 경우 "게임"코드를 서브 루틴에 넣고 완료되면 종료 한 다음 상위 레벨 루틴에서 새 게임이나 다른 것을 시작하도록했습니다.

관련 문제