2010-01-10 129 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的語言中,只需使用重構。