2012-02-04 108 views
0

我有班級甲板和遊戲卡。甲板對象必須有指針的動態分配的陣列,以遊戲牌對象:釋放指針數組的內存?

PlayingCard** _playing_cards; 

初始化此陣列中,甲板的構造,並建立()函數被稱爲:

Deck::Deck(int size) 
{ 
    _total_playing_cards = size; 
    _deal_next = 0; 
    build(); 
} 

void Deck::build() 
{ 
    _playing_cards = new PlayingCard*[_total_playing_cards]; 
    for(int i = 1; i <= _total_playing_cards; ++i) 
    { 
     _playing_cards[i-1] = new PlayingCard(i % 13, i % 4); 
    } 
} 

釋放與分配的存儲器「新」是在析構函數處理:

Deck::~Deck() 
{ 
    for(int i = 0; i < _total_playing_cards; ++i) 
    { 
     delete[] _playing_cards[i]; 
    } 
    delete[] _playing_cards; 
} 

我然後有一個單獨的文件,deck_test.cpp,其中有一個主()來簡單地構建和破壞一個甲板對象:

int main() 
{ 
    Deck deck(52); 
    deck.~Deck(); 
    return 0; 
} 

編譯沒有問題,但是在調試,Visual Studio的報告時 「在播放Cards.exe在0x5ab159da(msvcr100d.dll)未處理的異常:0000005:訪問衝突讀取位置0xfeeefee2」在查看調用堆棧時,問題似乎在我使用析構函數中'for'循環中的'delete []'運算符時發生。這不是從指針數組中釋放內存的正確方法嗎?

+0

在for循環中,不會刪除沒有[]的空格,因爲您正在刪除_playing_cards [i]指向的對象和對象? – octopusgrabbus 2012-02-04 19:39:43

回答

0

這是因爲兩件事情:

  1. 手動調用析構函數,然後當變量超出範圍的析構函數被再次調用。通常不應該手動調用析構函數,除非該對象被分配了new的位置,或者在它超出範圍之前,以潛在的方式重新構建了對象new(但不這樣做)。

  2. delete[] _playing_cards[i];應該delete _playing_cards[i]因爲playing_cards[i]不是一個數組,它只是一個new PlayingCard

而且,你爲什麼這樣做在一個地方i = 1; i <= _total_playing_cardsi = 0; i < _total_playing_cards在另一個?它不必要地使事情複雜化,我會建議選擇一個(最好是後者)並堅持下去。

1

請不要直接在main()中調用析構函數。

稍微修改析構函數代碼:

Deck::~Deck() 
{ 
    if (_playing_cards) { 
     for (std::size_t i = 0; i < _total_playing_cards; ++i) { 
      delete _playing_cards[i]; 
      _playing_cards[i] = NULL; 
     } 
     delete[] _playing_cards; 
     _playing_cards = NULL; 
    } 
} 

順便說一句,爲什麼不使用std::vector<PlayingCard>

+1

這不會幫助,你只是通過析構函數第二次解除引用NULL。 – 2012-02-04 19:40:50

+0

@謝謝,非常感謝你的評論。 – 2012-02-04 19:48:17

+0

你也不需要將'_playing_cards [i]'設置爲'NULL'。 – 2012-02-04 19:50:03

2

你的甲板析構函數需要如下:

Deck::~Deck() 
{ 
    for(int i = 0; i < _total_playing_cards; ++i) 
    { 
     delete _playing_cards[i]; 
    } 
    delete[] _playing_cards; 
} 

注意,在循環中,你必須使用一個非數組delete刪除一個撲克牌。

還有另外一個更大的問題,就是你要兩次調用析構函數 - 一次是在你的明確調用中,第二次是在main()結束時第二次出現在範圍之外。基本上,你不應該在C++中手動調用非堆分配對象的析構函數,因爲它會干擾C++對象的內置生命週期管理。糟糕的主意,除非你(一)真的知道你在做什麼,(二)你在非常特殊的情況下做。除此之外,使用動態分配的指針數組以及所帶來的所有開銷是一個壞主意,除非你正在學習指針並試驗它們。在生產代碼中,請給自己和其他人一個忙,並使用std :: vector來代替。

+0

同意使用矢量,但它是一個學術項目,所以我的手被束縛在我能夠和不能使用的東西上。 – 2012-02-04 19:50:31

+0

因此,評論「除非你正在學習指針」:)。在我看來,瞭解它們是一個好主意,但是在現代C++代碼中合法使用它們的人數遠遠少於人們相信的。 – 2012-02-04 19:53:36

0

你不必打電話給甲板〜甲板();由你自己。它會被自動調用。只需使用:

int main() 
{ 
    Deck deck(52); 
    return 0; 
} 

和使用的該delete _playing_cards[i]; for循環,如delete[]手段刪除陣列和delete意味着只刪除一個元素。