2009-07-04 78 views
1

這是我的addCard函數,它將一張紙牌作爲參數,然後將其自身的地址移交給分配給撲克對象的指針數組。析構函數問題

void cardHand::addCard(playingCard card) { 
    theHand[nElems++] = &card; 
} // addCard() 

現在,當我運行我的程序時,它運行良好,但當析構函數被調用時崩潰。

cardHand::~cardHand() { 
    for(int c = 0;c<MAX;c++) { 
     if(theHand[c] != NULL) 
      delete theHand[c]; // here is the problem 
    } 
    delete [] theHand; 
} // class destructor 

它崩潰了,因爲我只是在addCard函數中移交了撲克對象的地址。它應該是一個指針嗎?

+0

查看下面有關使用局部變量去使用new&()用法的人們的回答......說了這麼一句話,請確定您是否有相應的cardHand :: removeCard()方法,您將theHand [xyz ]刪除(刪除())到0時,否則您將嘗試刪除已刪除的對象。如果非null真的意味着它仍然是一個有效的對象,那麼在析構函數中的檢查是有價值的。另外,我會將NULL更改爲0 ... – Dan 2009-07-04 14:33:13

回答

7

的問題是在這裏

void cardHand::addCard(playingCard card) { theHand[nElems++] = &card; }

您存儲將在addCard方法結束時破壞的臨時卡對象的地址。

而在你的析構函數中,你試圖再次刪除它。

您有兩種選擇。

第一個:使addCard接受只是卡配置和newaddCard方法創建您的卡。
:用指針接受卡,但是你的cardHand的析構函數不能負責刪除卡。刪除將執行創建所有卡片的Deck對象。

1

它在delete上崩潰,因爲它從未分配過new

void cardHand::addCard(playingCard card) { 
    theHand[nElems++] = &card; 
} // addCard() 

在這個函數調用,您傳遞的遊戲牌的臨時副本,並採取其地址。除非你真的知道你在做什麼,否則存儲臨時對象的地址是一個禁忌。

相反,改變爲類似

/** @param card card to add. Takes ownership. */ 
void cardHand::addCard(playingCard *card) { 
    theHand[nElems++] = card; 
} // addCard() 

而在調用代碼,它傳遞一個playingCard對象的指針從new playingCard返回。

它仍然存在對象所有權轉移的問題,這是雙重刪除錯誤或內存泄漏的常見原因。使用代碼註釋來顯式傳輸這樣的傳輸是一個好習慣。

6

當你說:

theHand[nElems++] = &card; 

您存儲函數參數,這實際上是一個局部變量的地址。這總是一件壞事,在你試圖刪除它的時候會導致崩潰。

你可能想是這樣的:

theHand[nElems++] = new playingcCard(card); 

但真正的解決方案是使用遊戲牌的一個std ::載體,乾脆弄死動態分配。

1

所以給出其他答案,我的做法是交出一個參考或指向playingCard的指針。

而對於delete,一般規則是,你只有deletenew編輯的內容,即分配內存的人應該對其處置負責。 當然,與任何規則一樣,這也有例外,但這種行爲需要在界面合同中記錄得很好。

1

撲通的規則:只有刪除你分配什麼(或者與新的或memalloc)

因此,你的崩潰。

+1

我喜歡「撲通」規則:-) – 2009-07-04 10:12:56

1

它不起作用的原因是你在cardHand::addCard的價值傳遞你的課程。
因此,編譯器會在棧上構造類實例的臨時副本。
當它在堆棧上時,一旦addCard函數返回,它將自動清除。
您可以通過將您的playingCard實例作爲指針來解決此問題。
但是,正如在這篇文章中的其他人所說,建議不要delete東西,你沒有明確new

4

您正在使用C++作爲更好的C,雖然這對許多用途都很好,但它不是慣用的C++。

你真正想要的是完全消除動態分配。一般來說,如果你正在編寫C++,你應該很少使用new,甚至更少使用delete

你的手應該像這樣聲明:

std::vector<playingCard> hand; 

新卡應放在它是這樣的:

hand.push_back(card); 

你會發現,通過使用C++庫的集合類(和TR1智能指針),你永遠不需要使用newdelete - 直到你開始寫自己的智能指針。

+0

我也建議將簽名更改爲void cardHand :: addCard(const playingCard&card) – Niklas 2009-07-04 09:56:11