2013-04-28 150 views
2

我已经在C++编程了几个月了,当我经历论坛时,我发现了一个趋势。看来goto声明通常被认为是完全错误的使用,或者应该只在非常特定的情况下使用。什么是goto陈述,使他们从根本上错误?为什么goto语句在C++中被视为禁忌?

+3

您可能想从[这里]开始(http://en.wikipedia.org/wiki/Considered_harmful) – 2013-04-28 18:28:39

+0

* goto *语句不是“根本错误” - 优化的汇编代码充满了跳转目的。但是* goto *使代码难以被人读取 - 对于一台机器来说什么是好的对于人来说通常不是那么好。 – SChepurin 2013-04-28 18:48:14

+0

自20世纪60年代以来,Goto一直失宠。然而,一些着名作家,如Knuth,仍在使用它们。 – 2013-04-28 19:03:39

回答

7

最大的原因是它使代码难以遵循。 goto并不是不好的;使用它编写难以编写的代码很容易。

例如,您宁愿阅读哪一个?这:

int factorial(int n) { 
    int result; 

    if(n==0 || n==1) 
     result = 1; 
    else 
     result = n*factorial(n-1); 

    return result; 
} 

或者这样:

int factorial(int n) { 
    int result; 

    if(n > 1) 
     goto big; 

    result = 1; 
    goto end; 

big: 
    result = n*factorial(n-1); 

end: 
    return result; 
} 

的两种实现方式是一样的机器,但首先是更清楚我们的人的眼睛。虽然有时候goto更清晰。例如,在C考虑这个(或C++没有例外):

void process_big_file(FILE* foo) { 
    if(possible_failure_1(foo)) 
     goto cleanup; 

    // Do some work 

    if(possible_failure_2(foo)) 
     goto cleanup; 

    // Do some more work 

cleanup: 
    fclose(foo); 
} 

在这里,用goto是有道理的,因为它可以让你把所有的清理代码在一个地方,和goto 5事实上创建的逻辑流程执行。特别是在阅读代码时,很明显,您总是(a)达到清理代码,并且(b)总是达到清理代码,这是重要的。在没有例外情况下,我实际上认为goto在尝试组织(例如)清理代码时是正确的。

+2

最后一个例子不应该在C++中使用。即使没有例外,您也始终拥有与错误代码/早期退货一起工作的RAII。 – Pubby 2013-04-28 18:42:45

+0

作为一项规则,我同意,但有时RAII不适合。在这种情况下,你需要一个好的旧指针(甚至不需要'auto_ptr',它会为你实现RAII),然后你必须手动进行清理。一个很好的例子是带有循环引用的对象图,因为RAII类型对象和'auto_ptr'都使用(a)对象生命周期或(b)引用计数(分别)来执行清理。当然,有时候你会插入传统的C代码,然后所有的地狱都会崩溃。 :) – sigpwned 2013-04-28 18:48:12

+0

@sigpwned最后一个例子是设计不佳的代码的一个完美例子,其中一个函数做得太多。 – 2013-04-28 19:00:50

0

主要原因是goto使代码的推理非常困难,如果不是不可能的话。 (请注意,对于隐藏的goto也是如此,就像使用break从循环中间退出一样。)通常,如果您想要推理代码的正确性,则需要输入每个块在顶部,并将其留在底部。如果没有能够推断代码的正确性,则无法确定它是否正确。

+0

关于我所看到的主题的最佳解释。 – SChepurin 2013-04-29 05:28:43