当代码流是这样的:

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

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

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

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

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


当前回答

首先,一个简短的例子来说明为什么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函数接受大量参数,但如果您的类/结构具有良好的内聚性,这通常不是问题。(也就是说,属于一起的东西生活在一个对象中,所以这些函数可以作为指向少量对象的指针或引用,但仍然可以做很多有用的工作。)

其他回答

我不是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
}

也许就像这样

#define EVER ;;

for(EVER)
{
    if(!check()) break;
}

或者使用异常

try
{
    for(;;)
        if(!check()) throw 1;
}
catch()
{
}

使用异常还可以传递数据。

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

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

// edit 
doThingsAtEndAndReportErrorStatus()

我就是这么做的。

void func() {
  if (!check()) return;
  ...
  ...

  if (!check()) return;
  ...
  ...

  if (!check()) return;
  ...
  ...
}