do-while-false循环是常见的吗?

pat*_*ros 25 c c++ coding-style

前一阵子我改变了我处理c风格错误的方式.

我发现很多代码看起来像这样:

int errorCode = 0;

errorCode = doSomething();
if (errorCode == 0)
{
   errorCode = doSomethingElse();
}

...

if (errorCode == 0)
{
   errorCode = doSomethingElseNew();
}
Run Code Online (Sandbox Code Playgroud)

但最近我一直这样写:

int errorCode = 0;

do
{       
   if (doSomething() != 0) break;
   if (doSomethingElse() != 0) break;
   ...
   if (doSomethingElseNew() != 0) break;
 } while(false);
Run Code Online (Sandbox Code Playgroud)

我已经看到很多代码在出现错误后没有执行任何内容,但它始终以第一种方式编写.有没有其他人使用这种风格,如果你不这样做,为什么?

编辑:只是为了澄清,通常这个构造使用errno否则我会int在打破之前将值赋值给.此外,通常还有更多代码,而不仅仅是if (error == 0 )子句中的单个函数调用.但是,要考虑很多好点.

Ecl*_*pse 54

如果您使用的是C++,只需使用异常即可.如果您使用的是C,那么第一种风格效果很好.但如果你确实想要第二种风格,只需使用gotos - 这正是gotos真正是最清晰的结构的情况.

    int errorCode = 0;

    if ((errorCode = doSomething()) != 0) goto errorHandler;
    if ((errorCode = doSomethingElse()) != 0) goto errorHandler;
      ...
    if ((errorCode = doSomethingElseNew()) != 0) goto errorHandler;

    return;
errorHandler:
    // handle error
Run Code Online (Sandbox Code Playgroud)

是的,可能是糟糕的,并且每次调用后的异常或显式错误处理可能会更好,但是比使用另一个构造来尝试和模拟它们要好得多.使用gotos还可以为特定错误添加另一个错误处理程序:

    int errorCode = 0;

    if ((errorCode = doSomething()) != 0) goto errorHandler;
    if ((errorCode = doSomethingElse()) != 0) goto errorHandler;
      ...
    if ((errorCode = doSomethingElseNew()) != 0) goto errorHandlerSomethingElseNew;

    return;
errorHandler:
    // handle error
    return;
errorHandlerSomethingElseNew:
    // handle error
    return;
Run Code Online (Sandbox Code Playgroud)

或者,如果错误处理更多的是"展开/清理你所做的"变种,你可以像这样构造它:

    int errorCode = 0;

    if ((errorCode = doSomething()) != 0) goto errorHandler;
    if ((errorCode = doSomethingElse()) != 0) goto errorHandler1;
      ...
    if ((errorCode = doSomethingElseNew()) != 0) goto errorHandler2;

errorHandler2:
    // clean up after doSomethingElseNew
errorHandler1:
    // clean up after doSomethingElse
errorHandler:
    // clean up after doSomething
    return errorCode;
Run Code Online (Sandbox Code Playgroud)

这个习惯用法为您提供了不重复清理代码的优势(当然,如果您使用的是C++,RAII将更加干净地覆盖清理代码.

  • +1`goto`听起来很糟糕,但在这种情况下它才有意义. (15认同)
  • 如果您使用此成语来确保展开部分完成的工作,您通常会按照调用它们的相反顺序排列错误标签. (3认同)
  • 只要他正在检查的错误代码确实是"例外".例外情况对于灾难性错误是有利的,而不是正常的轧机条件. (3认同)

Gle*_*len 46

第二个片段看起来不错.你有效地重新发明了.

任何阅读第一种代码风格的人都会立即知道发生了什么,第二种风格需要更多检查,因此从长远来看会使维护更加困难,因为没有真正的好处.

编辑,在第二种风格,你已丢弃错误代码,所以你不能采取任何纠正措施或显示信息性的消息,记录有用的东西等....

  • @Shirkrin:如果你想要goto,那么**使用goto** - 不要误导读者暗示没有一个循环. (35认同)
  • 去?按照相同的逻辑,"if","for"和函数调用也是"glorified goto".我们对完整的"goto"添加限制以使其更有用 - "break"就是这样一种限制."do"可能会产生误导(循环?),但"goto"也会产生误导(跳转到任何地方?)."休息"具有特定的含义:逃避一个层面的背景. (10认同)
  • 不,转到不同.在这种情况下,他只是跳出当前的范围,因此没有什么可以出错. (9认同)
  • @Glen:不,不是很严厉.这是我第一个想到的事情.+1 (9认同)
  • 是的,这是一个转到.但是,我有一个实例,其中GOTO是正确的解决方案.(一.八年之内.)然而,这不是它. (2认同)
  • 所以也许答案是"是",你是唯一一个这样做的人 (2认同)

Pau*_*xon 16

第一种风格是经验丰富的眼睛同时出现的模式.

第二个需要更多的思考 - 你看它并看到一个循环.你期待几次迭代,但是当你读完它时,这个心理模型会被粉碎......

当然,它可能有用,但编程语言不仅仅是告诉计算机做什么的一种方式,它们也是将这些想法传达给其他人的一种方式.


rlb*_*ond 11

我认为第一个可以让您更好地控制如何处理特定错误.第二种方式只告诉你发生了错误,而不是它在哪里或是什么.

当然,例外优于两者......

  • 乔尔·斯波尔斯基(Joel Spolsky)抱怨异常是看不见的goto是:http://www.joelonsoftware.com/articles/Wrong.html (3认同)

Dig*_*oss 8

简洁,紧凑,易于快速阅读?

怎么样:

if ((errorcode = doSomething()) == 0
&&  (errorcode = doSomethingElse()) == 0
&&  (errorcode = doSomethingElseNew()) == 0)
    maybe_something_here;
return errorcode; // or whatever is next
Run Code Online (Sandbox Code Playgroud)

  • 我不知道我是否称之为"易于快速阅读". (6认同)