2011-08-30 67 views
2

我正在寫一個函數,它有很多返回點(取決於什麼條件是真實的),它在不同的點執行一堆new。在每個返回點,我需要做的一組delete是不同的。即使如此,我也不想在不同的地方做他們。什麼是處理這個問題的好方法?在C++(或任何其他語言)中優雅的控制流程

一些細節:讓我們考慮一個功能:

int MainClass::testFunction() { 
    numThreads++; 
    char *a = new char[100]; 
    // Some computation with a 
    if (condition1) { 
    numThreads--; 
    return -1; 
    } 
    char *b = new char[100]; 
    // Some computation with b 
    if (condition2) { 
    numThreads--; 
    return 42; 
    } 
    // Some more stuff. 
    numThreads--; 
} 

現在,return -1之前,我需要做的delete areturn 42之前,我需要做的delete a; delete b;。你可以想象如果我有多個返回點,這可能會變得複雜。

這裏是我的解決方案:

解決方案一:把所有刪除在函數結束時,把一些標籤,存儲在折返點的返回值,並使用goto(是的,骯髒的字眼!)到執行這些刪除後跳轉到適當的刪除並返回。

在上面的例子中,我可以說

superset: 
    delete b; 
subset: 
    delete a; 
numThreads--; 

並把goto supersetreturn 42goto subsetreturn -1之前。

我不喜歡這個解決方案,原因很明顯! :-)

第二種解決方案:我可以構建一個內部類實例,並對該類實例的變量執行new。像這樣...

int MainClass::testFunction() { 
    class Local { 
    char *a, *b; 
    Local() : a(NULL), b(NULL) {} 
    ~Local() { if (a != NULL) delete a; if (b != NULL) delete b; } 
    }; 
    Local l = Local(); 
    l.a = new char[100]; 
    // Some computation with a 
    if (condition1) { 
    return -1; 
    } 
    l.b = new char[100]; 
    // Some computation with b 
    if (condition2) { 
    return 42; 
    } 
} 

那麼,什麼問題呢?那麼,如何訪問該方法中的變量numThreads?我想在LocalnumThreads--的構造函數中執行numThreads++,在Local的驅動程序中。如果有幫助,testFunction也是另一個類的成員函數。

感謝您的閱讀。

更新:在堆棧上分配數組絕對是一種可能性,但我遇到堆棧溢出(ah ...這個網站的名稱:-))在堆棧上執行大的分配(堆棧大小爲線程是默認2MB)。我想在這個問題上解決的是一般資源獲取和銷燬。

回答

2

嗯。你是這樣過於複雜的。只需將ab設置爲NULL即可。圍繞整個事情與try/catch。如果出現任何問題,請拋出一些東西(任何事情都可以)。在catch塊中,在所有變量上調用delete。如果變量爲NULL,delete將不執行任何操作。

如果你需要做的東西,返回變量,理論上可以只throw返回值(是的,你可以扔掉整數)。然後當你完成清理時,只需返回拋出的值。

char *a = NULL, *b = NULL; 

try 
{ 
    a = ...; 
    if(bad_thing) 
     throw -1; 

    b = ...; 
    throw 42; 
} 
catch(int e) 
{ 
    delete[] a; 
    delete[] b; 
    return e; 
} 
+0

看起來很有希望。我會試試這個。順便說一下,在非'new'內存中刪除'會導致錯誤。我試過了。 :-) –

+1

刪除將只接受兩件事:由'new'返回的東西,或NULL。其他任何東西都是未定義的行爲。 –

4

什麼是處理這個問題的好辦法?

#include <vector> 
int MainClass::testFunction() { 
    numThreads++; 
    std::vector<char> a(100); 
    // Some computation with a 
    if (condition1) { 
    numThreads--; 
    return -1; 
    } 
    std::vector<char> b(100); 
    // Some computation with b 
    if (condition2) { 
    numThreads--; 
    return 42; 
    } 
    // Some more stuff. 
    numThreads--; 
} 
9

閱讀RAII

基本上,永遠不會使用new除了在構造函數(或轉讓),並且從來不使用delete除了在析構函數。

關於你提到的具體情況,你可以做到以下幾點:

(1)只要使用std::vector<char>
(2)改爲char a[100];(這是堆棧分配,因此會自動收集)。這隻有在100是一個常量時纔有效。您還可以將std::array<char, 100>與C++ 11編譯器一起使用(如果安裝了boost庫,則可以使用)。
(3)使用alloca()在堆棧上分配空間(如果100不是常量)(注意這一點)。
(4)編寫你自己的類,在構造函數中使用new分配內存,並在析構函數中使用delete刪除內存。

我會推薦(2)如果100是一個常數,不要太大,否則(1)。

+0

是的,這就是我想要做的......這個問題是這樣的:如何做到這一點。 –

+0

@Yogi Sharma:'#include ''std :: vector a(100);' – SigTerm

+0

@Yogi'vector'裏面有RAII內置於你的目的,你不必實現一個類。你可以像SigTerm的答案一樣使用'vector'。 –

0
int MainClass::imp_testFunction() { 

// perhaps break up a-compute, b-compute, some more stuff to 
// separate methods if they are nontrivial. 

// 100 chars should go on the stack (something like boost::array 
// is ideal if you can use that), unless you know you are 
// performing deep/recursive calls or have a small stack 
// (e.g. embedded). for large or variable sized allocations, 
// use something like a std::vector. 
    char a[100]; 

// Some computation with a 
    if (condition1) { 
     return -1; 
    } 

    char b[100]; 
// Some computation with b 
    if (condition2) { 
     return 42; 
    } 
// Some more stuff. 
} 

int MainClass::testFunction() { 
    // refactor this so you don't need to inc/dec at each exit. 
    ++numThreads; 
    const int ret(imp_testFunction()); 
    --numThreads; 
    return ret; 
} 
0

如果必須使用所有這回這個控制流程,一個解決方案可能是使用智能指針:

int MainClass::testFunction() { 
    numThreads++; 
    std::unique_ptr<char *> a(new char[100]); 
    // Some computation with a 
    if (condition1) { 
    numThreads--; 
    return -1; 
    } 
    std::unique_ptr<char *> b(new char[100]); 
    // Some computation with b 
    if (condition2) { 
    numThreads--; 
    return 42; 
    } 
    // Some more stuff. 
    numThreads--; 
} 

在最壞的和怪異的情況下,維持當前的控制流和不動a或b他們將在退出testFunction時被釋放。

相關問題