【问题标题】:Use of goto in this very specific case... alternatives?在这种非常特殊的情况下使用 goto ......替代方案?
【发布时间】:2018-01-28 11:30:22
【问题描述】:

我有一个关于在 C++ 代码中可能使用 goto 的问题:我知道应该尽可能避免使用 goto,但是在这种非常特殊的情况下,我很难找到好的替代品避免使用多个嵌套的 if-else 和/或其他二进制标志... 代码如下(只报了相关部分):

// ... do initializations, variable declarations, etc...

    while(some_flag) {
        some_flag=false;

        if(some_other_condition) {
            // ... do few operations (20 lines of code)

            return_flag=foo(input_args); // Function that can find an error, returning false
            if(!return_flag) {
                // Print error
                break; // jump out of the main while loop
            }

            // ... do other more complex operations
        }

        index=0;
        while(index<=SOME_VALUE) {
            // ... do few operations (about 10 lines of code)
            return_flag=foo(input_args); // Function that can find an error, returning false
            if(!return_flag) {
                goto end_here; // <- 'goto' statement
            }

            // ... do other more complex operations (including some if-else and the possibility to set some_flag to true or leave it to false
            // ... get a "value" to be compared with a saved one in order to decide whether to continue looping or not
            if(value<savedValue) {
                // Do other operations (about 20 lines of code)
                some_flag=true;
            }
            // ... handle 'index'
            it++; // Increse number of iterations
        }

        // ... when going out from the while loop, some other operations must be done, at the moment no matter the value of some_flag

        return_flag=foo(input_args);
        if(!return_flag) {
            goto end_here; // <- 'goto' statement
        }

        // ... other operations here
        // ... get a "value" to be compared with a saved one in order to decide whether to continue looping or not
        if(value<savedValue) {
            // Do other operations (about 20 lines of code)
            some_flag=true;
        }

        // Additional termination constraint
        if(it>MAX_ITERATIONS) {
            some_flag=false;
        }

        end_here:
        // The code after end_here checks for some_flag, and executes some operations that must always be done,
        // no matter if we arrive here due to 'goto' or due to normal execution.
    }
}

// ...

每次foo()返回false时,都不应再执行任何操作,代码应尽快执行最后的操作。另一个要求是这段代码,主要是while(index&lt;=SOME_VALUE)里面的部分,要尽可能快地运行,以保证整体性能良好。

正在使用“try/catch”块,其中try{} 包含大量代码(实际上,函数 foo() 仅在调用时才会产生错误,即仅在代码的两个不同点) 一个可能的选择?在这种情况下使用不同的“try/catch”块更好吗? 还有其他更好的选择吗?

提前非常感谢!

【问题讨论】:

  • 将清理工作包装在另一个函数中并调用 + return 而不是 goto?无论如何,您的功能似乎很长
  • 我怀疑 if 语句是否需要比 goto 慢;谁知道呢,它们最终可能会变成非常相似的机器代码。我还建议将函数分解为逻辑子单元(即函数)。这使流程更加清晰,这对于维护至关重要。如果你关心性能,这些函数可以内联! (也许使用关键字,当然还有适当的编译器设置。)
  • 是的,总共大约 250 行代码。主要问题还在于该代码位于特定 OMNeT++ 库中的特定函数(对模拟至关重要)中,并且它用于 OMNeT 模拟......“清理”代码实际上用于正确保存“解决方案” " 文件(使用 Win32 API)并删除所有临时文件,这就是为什么如果我没记错就应该始终执行它的原因:保留“已使用”的解决方案文件可能会导致完全模拟失败。
  • 在一个函数中包装清理可能是一个解决方案,但是......但因为这仅通过 Win32 API 调用完成,它实际上不需要任何额外的参数(至少,在这个实现),从“编码风格”的角度来看,添加一个 void clean(void) 函数会好吗?
  • @PeterA.Schneider 感谢您的评论。一般来说,避免“if”的事实与性能无关,而只是为了避免额外的嵌套 if-else 可能会使代码变得复杂,可读性差一些。还感谢您建议破坏内联函数中的代码。唯一的问题可能是必须向它们传递相当多的参数,但这肯定是为了让代码总体上更具可读性。

标签: c++ exception flags goto


【解决方案1】:

三个明显的选择:

  1. 坚持goto

  2. 将清理代码与某个 RAII 类的析构函数相关联。 (您可能可以将其写为 std::unique_ptr 的删除作为 lambda。)

  3. 将您的函数重命名为 foo_internal,并将其更改为 return。然后在调用foo_internal的新foo函数中编写清理程序

所以:

return_t foo(Args...) {
    const auto result = foo_internal(Args..);
    // cleanup
    return result;
}

一般来说,你的函数看起来太长了,需要分解成更小的部分。

【讨论】:

  • 谢谢!解决方案 3 似乎是一个非常好的解决方案,可以在我的案例中实现以避免 goto,并保持类似的代码结构。将函数拆分成更小的部分对于尝试提高整体可读性也很有用,但它需要例如具有大量参数的内联函数(因为代码的每个部分都使用在执行其他部分期间更新的标志和字符串)代码)......不过,我认为将这些标志作为本地全局变量会有所帮助。我一定会尝试分解整个函数!
  • “代码的每一部分都使用在代码的其他部分执行期间更新的标志和字符串”有代码气味:-)。理想情况下,代码将由松散耦合的部分组成;每个人都有一组有限的输入,并努力产生结果(而不是执行一些副作用)。您所描述的是长距离的紧密耦合;正如您刚刚经历的那样,这样的代码使维护和功能扩展变得困难。
【解决方案2】:

您可以这样做的一种方法是使用另一个 dummy 循环和break 像这样

 int state = FAIL_STATE;

 do {
     if(!operation()) {
         break;
     }

     if(!other_operation()) {
         break;
     }
     // ...
     state = OK_STATE;
 } while(false);

 // check for state here and do necessary cleanups

这样您就可以预先避免代码中的深层嵌套。

【讨论】:

    【解决方案3】:

    这是 C++!对非本地跳转使用异常:

    try {
        if(some_result() < threshold) throw false;
    }
    catch(bool) {
        handleErrors();
    }
    // Here follows mandatory cleanup for both sucsesses and failures
    

    【讨论】:

    • throw false 看起来很糟糕。
    • 不超过任何其他投掷。 :-)
    • 仅在确实是特殊情况时才推荐。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多