当代码流是这样的:

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

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

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

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

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


当前回答

如何移动if语句到一个额外的函数,产生一个数值或enum结果?

int ConditionCode (void) {
   if (condition1)
      return 1;
   if (condition2)
      return 2;
   ...
   return 0;
}


void MyFunc (void) {
   switch (ConditionCode ()) {
      case 1:
         ...
         break;

      case 2:
         ...
         break;

      ...

      default:
         ...
         break;
   }
}

其他回答

将其合并为一个if语句:

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

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

首先,一个简短的例子来说明为什么goto不是一个好的c++解决方案:

struct Bar {
    Bar();
};

extern bool check();

void foo()
{
    if (!check())
       goto out;

    Bar x;

    out:
}

试着把它编译成一个object文件,看看会发生什么。然后尝试等价的do+ break + while(0)。

这是题外话。主要观点如下。

如果整个函数失败,这些小块的代码通常需要某种类型的清理。当您“展开”部分完成的计算时,这些清理通常希望以与块本身相反的顺序发生。

获得这些语义的一个选项是RAII;参见@utnapistim的回答。c++保证自动析构函数以与构造函数相反的顺序运行,这自然提供了一个“unwind”。

但这需要大量的RAII类。有时一个更简单的选择是使用堆栈:

bool calc1()
{
    if (!check())
        return false;

    // ... Do stuff1 here ...

    if (!calc2()) {
        // ... Undo stuff1 here ...
        return false;
    }

    return true;
}

bool calc2()
{
    if (!check())
        return false;

    // ... Do stuff2 here ...

    if (!calc3()) {
        // ... Undo stuff2 here ...
        return false;
    }

    return true;
}

...等等。这很容易审计,因为它把“撤销”代码放在“做”代码旁边。简单的审计是好的。它还使控制流非常清晰。对于C来说,这也是一个有用的模式。

它可能要求calc函数接受大量参数,但如果您的类/结构具有良好的内聚性,这通常不是问题。(也就是说,属于一起的东西生活在一个对象中,所以这些函数可以作为指向少量对象的指针或引用,但仍然可以做很多有用的工作。)

类似于dasblinkenlight的答案,但避免了if语句中的赋值,这可能会被代码评审员“修复”:

bool goOn = check0();
if (goOn) {
    ...
    goOn = check1();
}
if (goOn) {
    ...
    goOn = check2();
}
if (goOn) {
    ...
}

...

当一个步骤的结果需要在下一步之前检查时,我使用这种模式,这与所有检查都可以在前面用一个大if(check1() && check2()…类型的模式。

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

//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
}

使用异常。您的代码将看起来更加清晰(并且创建异常正是为了处理程序执行流中的错误)。有关清理资源(文件描述符,数据库连接等),请阅读文章“为什么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;
}