我已经在使用C ++ SDL几天了,我遇到了一个有趣的问题。
SDL_Event event1;
while(SDL_WaitEvent(&event1))
{
for(size_t i = 0; i < MainMenuOptions.size();i++)
{
if(event1.button.x > MainMenuOptions.at(i).GetX() && event1.button.x < (MainMenuOptions.at(i).GetX() + MainMenuOptions.at(i).GetWidth())
&& event1.button.y > MainMenuOptions.at(i).GetY() && event1.button.y < (MainMenuOptions.at(i).GetY() + MainMenuOptions.at(i).GetHeight()))
{
break;
}
}
}
当我在for循环中使用break时,它将跳出for循环而不是while循环。如何在不使用goto语句的情况下突破while循环? (goto语句编程错误,我听说过)
答案 0 :(得分:11)
常见的解决方案是将这些东西放入自己的函数中并从中返回:
inline SDL_Event do_it()
{
SDL_Event event;
while(SDL_WaitEvent(&event))
for(std::size_t i = 0; i < MainMenuOptions.size(); ++i)
if(/*...*/)
return event;
return event; // or whatever else suits, I know too little about your code
}
答案 1 :(得分:7)
还有另一个答案,我认为我应该先说出来,然后每个人都会贬低我。 使用变量肯定是一个好的&#34;这样做的方式。然而,创建额外的变量只是为了跳出循环似乎有点矫枉过正,对吧?
是的,这一次goto
是完美的解决方案。它非常清楚你正在做什么,你没有使用另一个变量,代码仍然短,可维护和可读。
语句 goto是不好的做法主要是BASIC时代的残余,当时它是改变代码流的唯一方法。但是,现在我们更了解&#34;并且说goto
或任何其他结构都不好,只是没有削减它。对于你试图解决的一个特定问题,它可能是错误的(并且人们试图用goto解决的大多数问题就是这种情况)。但是,在适当的情况下(比如这里),没关系。当然,我不想在这里开始辩论。 Goto就像一个非常强大的工具(例如,大锤)。它有它的用途,你不能说工具是完全坏的;用户以错误的方式使用它。
答案 2 :(得分:4)
使用变量表示需要退出:
bool exit_program = false;
while( !exit_program && SDL_WaitEvent(&event1) )
{
for( /* ... */ )
{
exit_program = true;
}
}
答案 3 :(得分:4)
第一点:IMO,你试图将太多的东西包裹在一个地方,并最终得到一些相当难以理解的东西 - 有人必须仔细阅读整个长期的比较才能理解任何这应该完成的任何事情。
第二点:使用显式循环迭代标准集合通常是一个错误 - 这也不例外。标准库已经有一个算法来完成与循环相同的基本操作。最好使用它而不是自己再写一次。
template <class T>
bool in_range(T a, T b, T c) {
return (a > b) && (a < b+c);
}
class in_rect {
point p;
public:
in_rect(point const &p) : p(p) {}
// Not sure of the type of objects in MainMenuOptions, so just T for now.
//
bool operator()(T const &m) {
return in_range(p.x, m.GetX(), m.GetWidth())
&& in_range(p.y, m.GetY(), m.GetHeight());
}
};
SDL_Event event1;
while (SDL_WaitEvent(&event1))
if (std::any_of(MainMenuOptions.begin(), MainMenuOptions.end(),
in_rect(event1.button))
break;
一旦我们解决了其他问题,goto
就不再需要(甚至使用)了。我们没有采取任何明确意图删除它的步骤,但是当其他问题得到解决时(特别是用适当的算法替换循环),它的使用已经消失。
我想我应该预先评论代码行总数的增加:是的,还有更多的代码行。它是什么?如果我们真的想要,我们可以使用相同的基本方法,但不是定义in_rect
和in_range
,我们基本上只是从原始if
语句中取出条件并填充它变成一个lambda。虽然我非常高兴地将lambda添加到C ++中,但在这种情况下我对使用它并不感到兴奋。它会摆脱goto
,但一般来说代码几乎和它开始时一样难以理解。
简单地说,行数不是测量任何东西的好方法。
答案 4 :(得分:-1)
没有其他变量和goto
的解决方案:
while(SDL_WaitEvent(&event1))
{
size_t i;
for(i = 0; i < MainMenuOptions.size();i++)
{
if(/* ... */)
{
break;
}
}
if (i < MainMenuOptions.size())
break;
}