2010-01-10 83 views
3

一般来说goto是不好的(我们都知道为什么)什么是更好的方式来实现对错误的简单清理(如下例所示),而不必复制代码。在我看来,下面的代码是好的,我只是好奇,会做什么,别人:执行清理代码?

int main (int argc, const char * argv[]) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init] 
    int returnCode = 0; 

    // ... Other code 

    // WRITE: To file 
    if([dataStore writeToFile:savePathData atomically:YES] == NO) { 
     NSLog(@"writeToFile ... Error"); 
     returnCode = 1; 
     goto cleanUpCode; 
    } 

    // ... Other code 

    // Clean up 
    cleanUpCode: 
    [archiver release]; 
    [newPlanet release]; 
    [pool drain]; 
    return(returnCode); 
} 

EDIT_001:

一般来讲我同意@try,@catch,@finally比肯定更要走的路,但我确实有两个小问题。 (1)三个@try,@ catch,@finally块必须全部在一起,你没有在@catch和@finally之间放置代码的灵活性,你可能想绕过它。 (2)Obj-C 2.0的Apple文档声明如下:“重要:异常在Objective-C中是资源密集型的,不应该将异常用于一般的流控制,或者仅仅为了表示错误(例如一个文件不可访问)“。

多appcreciated

加里

+1

您可以将所有产生错误的代码包装到try-block中,并将所有清理代码放入catch-block中。 – 2010-01-10 20:31:04

+0

我经常使用这种格式。我认为它是goto的少数合法用途之一。 – 2010-01-10 22:31:17

回答

5

这是C代码常见的成语,我不觉得有什么不对的地方在没有更全面的创建/销毁语义的语言。

Goto在一般意义上被认为是有害的;它会使程序执行难以遵循。在这里,它的范围非常有限,并且流程是单向的。从某种意义上说它也是有帮助的,它允许你本地化你的清理代码,这是一件好事。

+3

更糟糕的是,他使用了objective-c,它有try/catch并且没有使用它。 – KevinDTimm 2010-01-10 20:54:37

4

那么,首先我会尝试将其重构为一些更多的方法,也许那么代码将不会如此难以辨认?

此外,您始终可以使用自动释放对象,因此您只需在末尾使用[pool drain]。这大概可以使用@try/@finally来完成,这样你就可以只用return 1而不是returnCode = 1

E.g.看看在Exception Handling and Memory Management文件(我知道你的问题是不是例外,但是这基本上都是一样的) - 他们建议是这样的:

- (void)doSomething { 
    NSMutableArray *anArray = nil; 
    array = [[NSMutableArray alloc] initWithCapacity:0]; 
    @try { 
     [self doSomethingElse:anArray]; 
    } 
    @finally { 
     [anArray release]; 
    } 
} 

个人而言,这是我会做什么。

+0

+1用于暗示重构 – 2010-01-10 20:51:17

-1

正如你所描述的东西看起来像一个小型的命令行程序,我不会担心它。因为当你的程序结束时,程序分配的所有内存将返回给系统(它将不复存在)。但是,如果你有一个更大的程序可以分配很多内容并运行一段时间,那么你可能会更加正确地进行清理,因为它可以帮助跟踪内存泄漏,这可能会影响运行较长时间的程序。在这种情况下,我也建议使用一些宏。

#define THROW(_name) goto label_ ## _name 
#define CATCH(_name) label_ ## _name: 

    : 
    : 

    if([dataStore writeToFile:savePathData atomically:YES] == NO) { 
     NSLog(@"writeToFile ... Error"); 
     returnCode = 1; 
     THROW(cleanUpCode); 
    } 

    : 
    : 

    CATCH(cleanUpCode) 

    [archiver release]; 
    [newPlanet release]; 
    [pool drain]; 
+1

为什么要引入这样的宏,如果实际上有'@ try'和'@ finally'这样的语言结构,导致代码更清晰?另外,我发现任何可能在阅读完代码后都会误导他人的名字会引起误解。一个月。 – 2010-01-10 20:47:20

+0

@ adam.wos当然,但我会说这取决于。它是什么类型的程序?正如他/她写的,我会说*保持简单*(不要太担心这是我的第一点) – epatel 2010-01-10 20:54:43

+0

哇,这太可怕了。 – KevinDTimm 2010-01-10 20:55:13

0

有很多方法可以做到这一点。这里有一对夫妇:

  1. 写出一个与您的主代码相对应的程序,例如: RunApplication。将该呼叫置于“其他”分支中。

  2. 把它放在try/catch中,在“catch”部分进行错误处理,否则进行正常处理。

代码

e.g. try { 
    .. check for error (any function/procedure that checks for an error can throw an exception 
.. do normal processing (still a good idea to factor this out into a procedure, for clarity 
} 
catch { 
    .. handle errors 
} 
finally 
{ 
    .. do cleanup 
} 

任何时候你认为你需要一个goto,一个错误的情况下,你可能会发现一个try/catch和异常效果更好。

在没有try/catch的语言中,只需使用重构。