2014-03-12 104 views
0

下面的delete語句是代碼冗餘。我想出了在多個if語句中相同的操作,如何減少代碼冗餘

int *a = new int[100] 
if (!doSomething1(a)) 
    delete[] a 
    return 
if (!doSomething2(a)) 
    delete[] a 
    return 
if (!doSomething3(a)) 
    delete[] a 
    return 

return 

一種選擇是:

if(doSomething1(a) || doSomething2(a) || doSomething3(a)) 
    ; 
delete[] a; 
return; 

但它不能在情況),適合在這裏我要添加指定doSomething1(指示,例如

if(!doSomething1(a)) 
    foo; 
    delete[] a; 
    return; 
if(!doSomething2(a)) 
    delete[] a; 
    return; 

我被告知至少有5種方法可以減少這種代碼冗餘。那麼有什麼建議?


更新,還有一個問題: 同樣的問題,讓我們來限制域僅C,注意流程邏輯的變化。

char *a = (char*)malloc(100*sizeof(char)); 
if(doSomething1(a)) 
    foo; 
    free(a) 
    return; 
if(doSomething2(a)) 
    free(a) 
    return; 
if(doSomething3(a)) 
    free(a); 
    return; 
free(a); 
return 

回答

2

爲什麼你需要手動刪除任何東西?這是C++,所以我們可以使用析構函數和RAII

std::vector<a>(100); 
if (!doSomething1(a)) 
    return; 
if (!doSomething2(a)) 
    return; 
if (!doSomething3(a)) 
    return; 

更普遍的:如果有什麼需要,當你離開一個範圍發生,那麼這樣做在該範圍內自動對象的析構函數。

但是,爲什麼你使用返回值來表示失敗?這是C++,所以我們可以使用例外:

std::vector<a>(100); 
doSomething1(a); 
doSomething2(a); 
doSomething3(a); 
+0

您的觀點是有效的,但我認爲他/她的問題是關於控制結構,而不是內存分配。我認爲內存分配對於任何代碼都只是一個通用的替身。 –

+0

Yesss !!!例外,所以* nobody *將看到代碼背後的扭曲控制流。 Dijkstra和你的「goto被認爲是有害的」,我們可以做得更多,更糟!拿着它!! **(邪惡的笑聲迴盪)** – vonbrand

+0

@IronSavior:答案在一般情況下是一樣的:如果在離開當前範圍時必須做某事,請在範圍自動對象的析構函數中執行。 –

0
do { 
    if (doSomething1(a) && doSomething2(a) && doSomething3(a)){ 
     break; /*all good: move outside the dummy loop*/ 
    } 
    /*one of the functions failed*/ 
    delete[] a; 
    return; 
} while (false); 

是單向的。我依賴的是if嚴格按照從左到右的順序評估報表,並在達到false後停止評估。

(這個習慣用法在C中很常用;請參閱unix內核源代碼)。

+1

就個人而言,我寧願看到一個真正的「goto」,而不是一個古怪的僞裝的;我寧願看到C++習慣用法比來自不同語言的習慣用法。 –

+0

@MikeSeymour:「goto」需要您爲初學者使用標籤;在這方面,'做'''更清潔。 – Bathsheba

+0

這不是'if'嚴格從左向右評估語句。這是無意義的。這就是邏輯運算符被短路。 – bolov

0
bool failure; 

int *a = new int[100] 
if (failure = !doSomething1(a)) 
    //... 
if (!failure && (failure = !doSomething2(a))) 
    //... 
if (!failure && (failure =!doSomething3(a))) 
    //... 

if (failure) 
{ 
    delete []a; 
    return; 
} 
//,,, 

return 
1

對於Google或SO,「RAII」和「範圍退出」是很好的搜索條件。例如,看看Boost.ScopeExitalternatives to it。這個想法是,你創建一個本地對象,並把它留給析構函數做清理或「最後」的代碼。

這裏是在直接運用成語的例子企圖,減少到最低限度(沒有錯誤檢查和類似的東西):

class AutomaticDeleter 
{ 
public: 
    AutomaticDeleter(int *a) : a(a) {} 
    ~AutomaticDeleter() { delete[] a; } 
    int *GetWrappedPointer() const { return a; } 
private: 
    int *a; 
}; 

// ... 

AutomaticDeleter automatic_deleter(new int[100]); 

if (!doSomething1(automatic_deleter.GetWrappedPointer())) 
    return; 
if (!doSomething2(automatic_deleter.GetWrappedPointer())) 
    return; 
if (!doSomething3(automatic_deleter.GetWrappedPointer())) 
    return; 

當然,我應該指出,這只是一個可以做什麼的示例,而不是應將應用於指針時所做的操作,特別是從new[]返回的指針。在現實生活中,你會使用std::vector<int>並完成它。該成語有更多有趣和有用的應用程序。

+0

這是一個很好的解釋,我無法完全理解MikeSeymou的答案。但是,由於MikeSeymour涵蓋了更多信息(但對於提出這類問題的人來說並不那麼簡單),我會選擇MikeSeymours作爲接受的答案。 – Sky

+0

@Sky:根本不是問題。我已經在Usenet中進行了數字社交,聲譽並未被表示爲暱稱旁邊顯示的數字。我必須承認我喜歡SO系統,但我知道一個人不應該被它帶走:) –