我创建了一个俄罗斯方块游戏,您可以在游戏结束后重新启动。我用goto实现了这个快速和脏(见代码)。 Game
类依赖于析构函数,这些是用这些goto调用的吗?这个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;
}
答案 0 :(得分:16)
您可以通过将此函数的大部分放在while
循环中,并设置一个标志来突破它来轻松避免这种情况。
在C中,goto
唯一真正“可接受”的用途是在出现错误时跳转到常见的清理代码。在C ++中,除了异常之外,你甚至可以避免这种情况。真的,没有任何借口!
答案 1 :(得分:13)
要回答有关析构函数的问题,似乎没有人覆盖过。根据6.6 / 2,将为您调用析构函数 。引用:
退出范围时(但是 完成),析构函数(12.4)是 要求所有构造的对象 具有自动存储持续时间 (3.7.2)(命名对象或临时对象) 在该范围内声明的,在 他们的相反顺序 宣言。转出一个循环, 走出街区,或回到过去 自动初始化变量 存储期限涉及到 用变量破坏变量 自动存储持续时间 转移点的范围 但没有转移到。
但是在这种情况下,我仍然不建议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;
}
答案 2 :(得分:6)
您可以将 newgame 标记中的所有内容放入函数中while循环的末尾,而不是goto。此函数的返回值将告诉您是否必须再次运行。所以它会是这样的:
...
srand(time(NULL));
while (runGame())
{
}
TTF_Quit();
...
您必须传递 runGame()您在游戏代码中使用的主函数中的任何参数,并返回1,其中代码使用 goto 和a当它是最后一场比赛时为零。
答案 3 :(得分:5)
将重要的块分解为函数,然后调用goto
而不是调用函数。
答案 4 :(得分:2)
Gotos很少使用。异常似乎是清理,你需要快速打破许多嵌套循环,释放一些内存并退出。这里可以很容易地用while循环替换。如果保留原样,只会使调试和维护变得更难。
答案 5 :(得分:0)
使用goto
有一些好时机(例如:实现状态机),但我不确定这是否真的是其中之一。
如果是我,我会把“游戏”代码放在一个子程序中,完成后退出它,然后让更高级别的例程选择开始一个新游戏。
答案 6 :(得分:-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;
}