无限循环和早期返回声明

时间:2010-12-20 14:48:50

标签: c++ infinite-loop

我有一个简单的控制台应用程序,它输出一个菜单并等待用户输入。执行适当的操作后,整个过程重复进行。输入特定字符串时,程序退出。这是通过无限循环和早期返回语句实现的:

int main()
{
    while (true)
    {
        OutputMenu();

        string UserChoice;
        cin >> UserChoice;

        // ...

        if (UserChoice == "exit") return 0;
    }
}

根据我的老师的说法,使用无限循环并使用return语句破解我的方法是不好的做法。他建议如下:

int main()
{
    bool ShouldExit = false;
    while (!ShouldExit)
    {
        OutputMenu();

        string UserChoice;
        cin >> UserChoice;

        // ...

        if (UserChoice == "exit") ShouldExit = true;
    }

    return 0;
}
  • 使用无限循环和早期返回语句真是个坏主意吗?
  • 如果是这样,是技术原因还是仅仅是不好的做法?

13 个答案:

答案 0 :(得分:11)

这可能是do...while适合的极少数情况之一。我避免添加额外的布尔状态变量,除非它们真正使代码更清晰。

int main()
{
    string UserChoice;
    do
    {
        OutputMenu();

        cin >> UserChoice;

        // ...

    } while (UserChoice != "exit");
}

但是,对于用户输入循环,我通常会创建一个函数来返回输入是否成功。如果cin关闭,代码很容易以无限循环结束。

E.g。

bool GetNonExitInput( std::istream& in, std::string& s )
{
    OutputMenu();
    in >> s;

    return in.good() && s != "exit";
}


int main()
{
    std::string UserChoice;

    while (GetNonExitInput(std::cin, UserChoice))
    {
        // ...
    }
}

答案 1 :(得分:7)

真的要么很好,但你需要做你教授想做的事。你会发现它在工业上也是一样的。一些公司可能有一个编码标准,规定花括号在一个新的线上,而其他公司希望他们从开始阻止的线开始。没有理由倾向于选择其中一个,所以最好只选择领导者想要的东西。

答案 2 :(得分:6)

这两种方法的唯一区别在于,在第二种方法中,在退出while循环后仍然可以执行某些操作,而在第一种方法中,您将从函数本身返回; while之后你无能为力。

但是,我建议使用这个简单的代码:您也可以使用break代替维护变量:

while (true)
{
       //your code

       if (UserChoice == "exit") 
            break;

       //your code
}

不再需要变量ShouldExit

答案 3 :(得分:5)

取决于语言。如果你用C语言写作,那么“一个入口,一个退出”的理念是有意义的 - 你想要一个地方,你正在清理一个函数使用的资源,这样你就没有机会忘记以后了。如果您使用的是C ++,那么无论如何您应该使用RAII进行清理,在这种情况下,我完全不同意您的老师。根据需要使用return,以使代码尽可能清晰。

(虽然我会在C ++中使用for (;;)代替while (true)来生成无限循环)

答案 4 :(得分:2)

使用受控变量,您可以在退出函数之前处理退出条件(while之后的代码)。

答案 5 :(得分:2)

在我看来,两种方式都很好,但第二种方式更“漂亮”。

在编程中,以您能想到的最简单的方式编写代码非常重要,并且如果您将被替换或出于任何其他原因,使其他程序员能够轻松理解您的代码。

你的两个代码没有涉及复杂性问题,所以他们都很好,就像我说的那样,但我认为我不喜欢第一个代码就是使用'return'语句,而不需要'return'这里的陈述。

还有另一种方式来编写这段代码,比你的方式更好(在我看来),但不如你老师那样好。

int main()
{
    bool ShouldExit = false;
    while ( true )
    {
        OutputMenu();

        string UserChoice;
        cin >> UserChoice;

        // ...

        if (UserChoice == "exit") break;
    }
}

我不喜欢你的第一个代码和我上面的代码的另一个主要原因是因为使用了无限循环,当你习惯于无限循环时,只是时间问题才会让你变得更复杂其中有重大错误的程序。

再一次 - 我所写的所有事情都仅在我看来,而不是福音真理。

Rotem公司

答案 6 :(得分:1)

从技术上讲,只要没有代码,你就可以通过使用返回来跳过它。

然而,如果只是因为“ShouldExit”的明显含义,你老师的建议更具可读性。

答案 7 :(得分:1)

我认为你的老师意味着退出条件很容易维持。这是因为while循环后的代码清理。如果你要做一个硬回车,那么while循环之后的所有东西都不会被执行。这可以通过使用break而不是return来阻止。

int main()
{
 //create a file

 while (true)
 {
  OutputMenu();

  string UserChoice;
  cin >> UserChoice;

  //write UserChoice to file

  // ...

  if (UserChoice == "exit") return 0;
 }

 //close file 
}

//close file将不会被执行!

答案 8 :(得分:1)

break语句专门用于退出循环。

答案 9 :(得分:1)

我通常更喜欢老师建议的内容,因为它更容易阅读并理解停止循环的条件。
如果你有一个带有return语句的无限循环,对于那些没有编写代码的人来说,通过代码并找出程序何时命中return语句会有点困难。

此外,我通常不喜欢早期返回,因为维护代码的人很容易引入错误,例如:

int main()
{
    // code added by some other programmer:
    importantInitialization();

    while (true)
    {
        OutputMenu();

        // code added by some other programmer:
        Something *st = new Something();

        string UserChoice;
        cin >> UserChoice;

        // ...

        if (UserChoice == "a") runA();
        else if (UserChoice == "b") runB();
        else if (UserChoice == "c") runC();
        else if (UserChoice == "d") runD();
        else if (UserChoice == "exit") return 0;
        else if (UserChoice == "help") showHelp();

        // code added by some other programmer:
        delete st; // this would not run on the last loop
    }

    // code added by some other programmer:
    importantCleanUp(); // this would never run 
}

当然,在这种特殊情况下,很容易看到问题,但是当维护一个更复杂的功能时,你可以看到早期的返回语句如何使它更容易出现像这样的缺乏注意力的错误。

答案 10 :(得分:1)

我认为休息时间(真实)最好是出于几个原因。引入存储退出条件的变量很容易出错,更多变量意味着更多可能出错。 break语句也专门用于断开循环。最后,与(;;)相反,while(true)是干净,可读和简洁的,其中(;;)试图在没有充分理由的情况下变得聪明。

为了增加一点,为了提高可读性和理解力,尽可能将退出条件放在最接近循环顶部的位置:

while (true) {

    OutputMenu();

    string UserChoice;
    cin >> UserChoice;

    if (UserChoice == "exit")
        break;

    // process other options here
}

答案 11 :(得分:1)

在状态分析方面,使用本地标志的例程相当于相同的代码,复制两次,其中一个副本对应于该标志为真,另一个副本等同于该标志为假,以及任何改变它们之间跳跃的旗帜状态的代码。如果有n个标志,则相当于2 ^ n个代码副本(尽管如果某些标志是互斥的,则其中一些可能无法访问且不相关)。

虽然有时候标志是最实用的做事方式,但它们会增加代码的复杂性。当确实需要复杂性时,标志可能是提供它的最简洁方式。当有一种干净实用的方法来编写避免标记的代码时,应该这样做。有时可能不清楚使用或避免使用标志是否更好(例如

  flag = condition_which_must_be_tested_here();
  action_which_will_disturb_the_condition();
  if (flag)
    do_something();
  else
    do_something_else();

  if (condition_which_must_be_tested_here())
  {    
    action_which_will_disturb_the_condition();
    do_something();
  }
  else
  {    
    action_which_will_disturb_the_condition();
    do_something_else();
  }

但是如果没有标志就可以编写代码并且不需要复制任何内容,那么通常更喜欢这样的版本。

答案 12 :(得分:0)

我在哲学上反对while(true)。这意味着“永远循环”,你永远不会永远想要循环。

另一方面,我也哲学上反对布尔变量,它只记录可以通过其他方式找到的状态。等待中有一个错误,它可能并不总是与它应该反映的状态正确同步。在这种情况下,我更喜欢代码:

int main()
{
    string UserChoice = "not started"; // or empty string
    while (UserChoice != "exit")
    {
        OutputMenu();

        string UserChoice;
        cin >> UserChoice;

        // ...

    }

    return 0;
}