2010-01-21 48 views
2

我已經開始編寫一個簡單的控制檯Yahtzee遊戲進行練習。我只是有一個關於這個函數是否會泄漏內存的問題。每次需要重新滾動骰子時都會調用滾動函數。C++會這個函數泄漏嗎?

它所做的是創建一個動態數組。第一次使用它會存儲5個隨機值。對於下一次運行,除了您想要保留的骰子外,它只會重新展開。我有另一個功能,但因爲它是不相關的這個問題,我離開了出來

主要功能

int *kast = NULL;   //rolled dice 
int *keep_dice = NULL; //which dice to re-roll or keep 

kast = roll(kast, keep_dice); 
delete[] kast; 

與這裏的功能

int *roll(int *dice, int *keep) { 

    srand((unsigned)time(0)); 
    int *arr = new int[DICE]; 
    if(!dice) 
    { 
     for(int i=0;i<DICE;i++) 
     { 

      arr[i] = (rand()%6)+1; 
      cout << arr[i] << " "; 
     } 
    } 
    else 
    { 
     for(int i=0;i<DICE;i++) 
     { 
      if(!keep[i]) 
      { 
       dice[i] = (rand()%6)+1; 
       cout << "Change "; 
      } 
      else 
      { 
       keep[i] = 0; 
       cout << "Keep "; 
      } 
     } 
     cout << endl; 
     delete[] arr; 
     arr = NULL; 
     arr = dice; 

    } 
    return arr; 
} 
+4

有人告訴過你在刪除它們後總是給NULL指定NULL嗎?他們錯了。 – 2010-01-21 15:27:47

+0

'arr = NULL; arr =骰子;'相當多餘。 :]如果即使只進行了第一級優化,該行也不會存在於編譯後的輸出中。 ('arr = NULL;') – GManNickG 2010-01-21 15:35:47

+0

@Steve:我記得在書中讀到它。是什麼讓它錯了?我認爲這只是出於安全原因。 – jasonline 2010-01-21 15:35:57

回答

12

是的,它可以泄漏。舉例來說,使用cout可能會引發異常,如果是,則不會調用delete

而不是自己分配一個動態數組,您可能需要考慮返回一個std::vector。更好的是,把你的函數變成一個適當的算法,它需要一個迭代器(在這種情況下,一個back_insert_iterator)並在那裏寫輸出。

編輯:仔細看看它,我覺得有必要指出我完全不喜歡這段代碼的基本結構。你有一個功能是真正做兩種不同的事情。你也有一對你並行尋址的數組。我將它重構成兩個獨立的函數,一個roll和一個re_roll。我重組數據作爲結構的數組:

struct die_roll { 
    int value; 
    bool keep; 

    die_roll() : value(0), keep(true) {} 
}; 

執行初始輥,傳遞一個矢量(或陣列,如果你真的堅持)的這些給roll功能,其填充在初始值。要進行重新滾動,您將向量傳遞到re-roll,該滾動重新滾動以獲得任何die_roll的新值,其keep成員已設置爲false

+0

或者,使用'auto_ptr'是有益的。 – 2010-01-21 15:26:11

+0

Sry沒有提到那些cout只用於錯誤檢查。無論如何,除了這是防泄漏的功能和陣列刪除正確? – starcorn 2010-01-21 15:29:57

+1

@klw:是的,只要你確保在分配和釋放內存之間不會拋出異常,你的代碼應該沒有內存泄漏。但是,這種情況意味着您的代碼(無雙關語意思)充其量是非常脆弱的。 – 2010-01-21 15:37:09

4

使用(重新建立了新分配)std::vector而不是數組,並將其引用傳遞給該函數。這樣,你就可以確定它不會泄漏。

+0

我已經考慮使用矢量,但由於我已經知道我想要多大的列表,我認爲使用數組會更好。 – starcorn 2010-01-21 15:30:41

+0

@klw:什麼?這沒有意義。一個'std :: vector'是你的代碼的標準和安全版本,知道大小沒有意義,只需在vector上調用'resize'或'reserve'即可。 – GManNickG 2010-01-21 15:38:11

+0

確實;如果你使用正確的構造函數,那麼不需要重新分配,你不會爲這些支付費用。它可能和數組一樣快,而且更容易一些。 – Thomas 2010-01-21 15:41:42

4

分配內存的方式很混亂:在函數內部分配的內存必須由函數外部的代碼釋放。

爲什麼不重寫它是這樣的:

int *kast = new int[DICE];   //rolled dice 
bool *keep_dice = new bool[DICE]; //which dice to re-roll or keep 
for (int i = 0; i < DICE; ++i) 
    keep_dice[i] = false; 

roll(kast, keep_dice); 

delete[] kast; 
delete[] keep_dice; 

這符合你的new S和delete很好s上行。至於功能:因爲我們設置keep_dice所有false,參數都不爲過NULL,它總是修改dice,而不是返回一個新數組,它簡化爲:

void roll(int *dice, int *keep) { 
    for(int i=0;i<DICE;i++) 
    { 
     if(keep[i]) 
     { 
      keep[i] = false; 
      cout << "Keep "; 
     } 
     else 
     { 
      dice[i] = (rand()%6)+1; 
      cout << "Change "; 
     } 
    } 
    cout << endl; 
} 

此外,你應該移動srand通話到你程序的開始。重播對於隨機性非常不利。

+0

感謝您的輸入 – starcorn 2010-01-21 15:41:52

0

我的建議是花時間購買/借閱並閱讀Scott Meyers Effective C++ 3rd Edition。爲了成爲富有成效的C++程序員,你將會節省數月的痛苦。我從個人痛苦的經歷中發言。

+0

感謝您的建議 – starcorn 2010-01-21 21:36:12