代码之家  ›  专栏  ›  技术社区  ›  jrharshath

如何从开关内部脱离回路?

  •  94
  • jrharshath  · 技术社区  · 17 年前

    我在写一些类似这样的代码:

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

    有什么直接的方法吗?

    我知道我可以使用一个标志,并通过在开关之后放置一个条件中断来中断循环。我只是想知道C++是否已经有了一些构造。

    19 回复  |  直到 17 年前
        1
  •  52
  •   Juan Delgado    7 年前

    前提

    无论语言或所需功能如何,以下代码都应被视为不正确的形式:

    while( true ) {
    }
    

    支持性论点

    这个 while( true ) 循环的形式不好,因为它:

    • 中断while循环的隐含协定。
      • while循环声明应显式声明 只有 退出条件。
    • 意味着它永远循环。
      • 必须读取循环中的代码才能理解终止子句。
      • 永远重复的循环会阻止用户从程序中终止程序。
    • 效率低下。
      • 有多个回路终止条件,包括检查“真”。
    • 容易出现错误。
      • 无法轻松确定将始终为每个迭代执行的代码放在何处。
    • 导致不必要的复杂代码。
    • 自动源代码分析。
      • 若要查找错误、程序复杂性分析、安全检查,或在不执行代码的情况下自动派生任何其他源代码行为,指定初始中断条件允许算法确定有用的不变量,从而改进自动源代码分析度量。
    • 无限循环。
      • 如果每个人都使用 while(true) 对于非无限循环,当循环实际上没有终止条件时,我们将失去简洁通信的能力。(可以说,这已经发生了,所以这一点还没有定论。)

    替代“转到”

    以下代码的形式更好:

    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 方法,它允许子类重写默认行为(使用嵌入的 转换 和 古托 )

    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 导致代码误导和过于复杂。

        2
  •  144
  •   Mehrdad Afshari    17 年前

    你可以使用 goto .

    while ( ... ) {
       switch( ... ) {
         case ...:
             goto exit_loop;
    
       }
    }
    exit_loop: ;
    
        3
  •  49
  •   sakra    17 年前

    另一种解决方案是使用关键字 continue 与 break ,即:

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

    使用 持续 语句完成希望循环继续的每个case标签,并使用 打破 语句完成应终止循环的大小写标签。

    当然,只有在switch语句之后没有要执行的额外代码时,此解决方案才有效。

        4
  •  20
  •   Alterlife    17 年前

    要做到这一点,一个整洁的方法是把它变成一个函数:

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

    可选(但“坏做法”):如前所述,您可以使用goto,或在开关内引发异常。

        5
  •  13
  •   Dave Jarvis James Eichele    13 年前

    在C++中没有“双断线”或类似的构造。最接近的是 goto -虽然它的名字有着不好的内涵,但它在语言中的存在是有原因的——只要它被小心而谨慎地使用,它就是一个可行的选择。

        6
  •  8
  •   Adam Pierce    17 年前

    您可以将开关置于如下单独的功能中:

    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())
        ;
    
        7
  •  7
  •   Community Mohan Dere    9 年前

    即使您不喜欢goto,也不要使用异常来退出循环。下面的示例显示了它有多难看:

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

    我会用 goto 如在 this 回答。在这种情况下 转到 将使代码比任何其他选项更清晰。我希望 this 这个问题会有帮助。

    但我认为使用 古托 是唯一的选项,因为字符串 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 ...
    }
    
        8
  •  5
  •   sharptooth    17 年前

    在这种情况下,没有用于跳出循环的C++构造。

    或者使用一个标志来中断循环,或者(如果合适)将代码提取到一个函数中并使用 return .

        9
  •  2
  •   Dave Jarvis James Eichele    13 年前

    您可能会使用goto,但我希望设置一个停止循环的标志。然后断开开关。

        10
  •  2
  •   Mark B    13 年前

    为什么不修复while循环中的条件,使问题消失?

    while(msg->state != DONE)
    {
        switch(msg->state) {
        case MSGTYPE: // ... 
            break;
        // ... more stuff ...
        case DONE:
            // We can't get here, but for completeness we list it.
            break; // **HERE, I want to break out of the loop itself**
        }
    }
    
        11
  •  2
  •   Prashanth Sriram    9 年前

    不,C++没有一个构造,因为关键字“中断”已经被保留用于退出开关块。或者,带有退出标志的do..while()就足够了。

    do { 
        switch(option){
            case 1: ..; break;
            ...
            case n: .. ;break;
            default: flag = false; break;
        }
    } while(flag);
    
        12
  •  1
  •   ercan    12 年前

    我想;

    while(msg->state != mExit) 
    {
        switch(msg->state) 
        {
          case MSGTYPE: // ...
             break;
          case DONE:
          //  .. 
          //  ..
          msg->state =mExit;
          break;
        }
    }
    if (msg->state ==mExit)
         msg->state =DONE;
    
        13
  •  0
  •   SpiriAd    16 年前

    最简单的方法是在进行切换之前设置一个简单的if,然后测试退出循环的条件……尽可能简单

        14
  •  0
  •   Daniel Trebbien    15 年前

    这个 break C++中的关键字只终止最嵌套的封闭迭代或 switch 语句。因此,你不能脱离 while (true) 直接在 转换 语句;不过,您可以使用以下代码,我认为这是解决此类问题的一个很好的模式:

    for (; msg->state != DONE; msg = next_message()) {
        switch (msg->state) {
        case MSGTYPE:
            //...
            break;
    
        //...
        }
    }
    

    如果你需要做些什么 msg->state 等于 DONE (例如运行清理例程),然后在 for 循环;即,如果您当前有:

    while (true) {
        switch (msg->state) {
        case MSGTYPE:
            //... 
            break;
    
        //...
    
        case DONE:
            do_cleanup();
            break;
        }
    
        if (msg->state == DONE)
            break;
    
        msg = next_message();
    }
    

    然后使用:

    for (; msg->state != DONE; msg = next_message()) {
        switch (msg->state) {
        case MSGTYPE:
            //...
            break;
    
        //...
        }
    }
    
    assert(msg->state == DONE);
    do_cleanup();
    
        15
  •  0
  •   Mark A. Donohoe    15 年前

    令人惊讶的是,考虑到解释的深度,这是多么简单…这是你所需要的…

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

    大声笑!真的!这就是你所需要的!一个额外的变量!

        16
  •  0
  •   Wajeed Shaikh    15 年前
    while(MyCondition) {
    switch(msg->state) {
    case MSGTYPE: // ... 
        break;
    // ... more stuff ...
    case DONE:
       MyCondition=false; // just add this code and you will be out of loop.
        break; // **HERE, you want to break out of the loop itself**
    }
    }
    
        17
  •  0
  •   Ram Suthar    10 年前

    我也遇到了同样的问题,用旗子解决了。

    bool flag = false;
    while(true) {
        switch(msg->state) {
        case MSGTYPE: // ... 
            break;
        // ... more stuff ...
        case DONE:
            flag = true; // **HERE, I want to break out of the loop itself**
        }
        if(flag) break;
    }
    
        18
  •  -2
  •   Andrei Vajna II    17 年前

    如果我还记得C++语法,你可以添加一个标签 break 陈述,就像 goto . 所以你想要的东西很容易写出来:

    while(true) {
        switch(msg->state) {
        case MSGTYPE: // ...
            break;
        // ... more stuff ...
        case DONE:
            break outofloop; // **HERE, I want to break out of the loop itself**
        }
    }
    
    outofloop:
    // rest of your code here
    
        19
  •  -3
  •   Flexo - Save the data dump sunny moon    14 年前
      while(true)
      {
        switch(x)
        {
         case 1:
         {
          break;
         }
        break;
       case 2:
        //some code here
       break;
      default:
      //some code here
      }
    }