当代码流是这样的:

if(check())
{
  ...
  ...
  if(check())
  {
    ...
    ...
    if(check())
    {
      ...
      ...
    }
  }
}

我通常看到这种方法可以避免上述混乱的代码流:

do {
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
} while(0);

有什么更好的方法可以避免这种工作/黑客,从而使其成为更高级别(行业级别)的代码?

任何跳出盒子的建议都是欢迎的!


当前回答

我不是c++程序员,所以我不会在这里写任何代码,但到目前为止还没有人提到面向对象的解决方案。下面是我的猜测:

拥有一个通用接口,该接口提供了一个方法来评估单个条件。现在,您可以在包含有问题的方法的对象中使用这些条件的实现列表。遍历列表并计算每个条件,如果其中一个条件失败,可能会提前爆发。

这样的设计很好地遵循了开/闭原则,因为在初始化包含相关方法的对象时,可以很容易地添加新的条件。您甚至可以向接口添加第二个方法,该方法用于条件评估,返回条件的描述。这可以用于自文档系统。

但是,缺点是由于使用了更多的对象和遍历列表,所涉及的开销稍微多一些。

其他回答

为什么标记法没有被回答,这是自古以来使用的方法。

//you can use something like this (pseudocode)
long var = 0;
if(condition)  flag a bit in var
if(condition)  flag another bit in var
if(condition)  flag another bit in var
............
if(var == certain number) {
Do the required task
}

如果你不需要在执行过程中引入局部变量,那么你通常可以将其平化:

if (check()) {
  doStuff();
}  
if (stillOk()) {
  doMoreStuff();
}
if (amIStillReallyOk()) {
  doEvenMore();
}

// edit 
doThingsAtEndAndReportErrorStatus()

将其合并为一个if语句:

if(
    condition
    && other_condition
    && another_condition
    && yet_another_condition
    && ...
) {
        if (final_cond){
            //Do stuff
        } else {
            //Do other stuff
        }
}

这是在Java等语言中使用的模式,其中删除了goto关键字。

使用异常。您的代码将看起来更加清晰(并且创建异常正是为了处理程序执行流中的错误)。有关清理资源(文件描述符,数据库连接等),请阅读文章“为什么c++不提供一个“finally”结构?”

#include <iostream>
#include <stdexcept>   // For exception, runtime_error, out_of_range

int main () {
    try {
        if (!condition)
            throw std::runtime_error("nope.");
        ...
        if (!other condition)
            throw std::runtime_error("nope again.");
        ...
        if (!another condition)
            throw std::runtime_error("told you.");
        ...
        if (!yet another condition)
            throw std::runtime_error("OK, just forget it...");
    }
    catch (std::runtime_error &e) {
        std::cout << e.what() << std::endl;
    }
    catch (...) {
        std::cout << "Caught an unknown exception\n";
    }
    return 0;
}

当然不是答案,而是一个答案(为了完整起见)

而不是:

do {
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
} while(0);

你可以这样写:

switch (0) {
case 0:
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
}

这仍然是一个伪装的goto,但至少它不再是一个循环。这意味着你不需要非常仔细地检查是否有一些继续隐藏在块的某处。

构造也非常简单,您可以希望编译器会优化它。

正如@jamesdlin所建议的,你甚至可以把它隐藏在一个宏后面

#define BLOC switch(0) case 0:

然后像这样使用它

BLOC {
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
    if(!check()) break;
    ...
    ...
}

这是可能的,因为C语言语法期望在开关之后有一个语句,而不是一个括号中的块,并且您可以在该语句之前放置一个case标签。到目前为止,我还没有看到允许这样做的意义,但在这种特殊情况下,将开关隐藏在一个漂亮的宏后面是很方便的。