析构函数问题

问题描述:

这是我的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

的问题是在这里

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

您存储将在addCard方法结束时破坏的临时卡对象的地址。

而在你的析构函数中,你试图再次删除它。

您有两种选择。

第一个:使addCard接受只是卡配置和newaddCard方法创建您的卡。
:用指针接受卡,但是你的cardHand的析构函数不能负责删除卡。删除将执行创建所有卡片的Deck对象。

它在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返回。

它仍然存在对象所有权转移的问题,这是双重删除错误或内存泄漏的常见原因。使用代码注释来显式传输这样的传输是一个好习惯。

当你说:

theHand[nElems++] = &card; 

您存储函数参数,这实际上是一个局部变量的地址。这总是一件坏事,在你试图删除它的时候会导致崩溃。

你可能想是这样的:

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

但真正的解决方案是使用游戏牌的一个std ::载体,干脆弄死动态分配。

所以给出其他答案,我的做法是交出一个参考或指向playingCard的指针。

而对于delete,一般规则是,你只有deletenew编辑的内容,即分配内存的人应该对其处置负责。 当然,与任何规则一样,这也有例外,但这种行为需要在界面合同中记录得很好。

扑通的规则:只有删除你分配什么(或者与新的或memalloc)

因此,你的崩溃。

+1

我喜欢“扑通”规则:-) – 2009-07-04 10:12:56

它不起作用的原因是你在cardHand::addCard的价值传递你的课程。
因此,编译器会在栈上构造类实例的临时副本。
当它在堆栈上时,一旦addCard函数返回,它将自动清除。
您可以通过将您的playingCard实例作为指针来解决此问题。
但是,正如在这篇文章中的其他人所说,建议不要delete东西,你没有明确new

您正在使用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