这是我的addCard函数,它将一个playCard作为参数,然后将其self的地址移交给一个分配给playCard对象的指针数组。
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函数中移交了playingCard对象的地址。它应该是指针吗?
答案 0 :(得分:7)
问题出在这里
void cardHand::addCard(playingCard card) { theHand[nElems++] = &card; }
存储将在addCard方法结束时销毁的临时卡对象的地址。
在你的析构函数中,你试图再次删除它。
您有两种选择。
首先:让addCard接受卡片配置,并使用new
方法使用addCard
创建卡片。
第二:通过指针接受卡,但是您的cardHand的析构函数不能负责删除卡。删除将执行创建所有卡的Deck对象。
答案 1 :(得分:6)
当你说:
theHand[nElems++] = &card;
您正在存储函数参数的地址,该参数实际上是一个局部变量。这总是一件坏事,在您的情况下,当您尝试删除它时会导致崩溃。
您可能需要以下内容:
theHand[nElems++] = new playingcCard( card );
但真正的解决方案是使用playCard的std :: vector并完全取消动态分配。
答案 2 :(得分:4)
你使用C ++作为一个更好的C,虽然这很好用于很多目的但它不是惯用的C ++。
你真正想要的是完全取消动态分配。一般来说,如果你正在编写C ++,你应该很少使用new
,甚至更少使用delete
。
你的手应该被宣布为:
std::vector< playingCard > hand;
应该用这样的东西放上新卡:
hand.push_back( card );
您应该通过使用C ++库的集合类(以及TR1智能指针)来发现,您永远不需要使用new
或delete
- 直到您无论如何都要编写自己的智能指针。
答案 3 :(得分:1)
它在delete
上崩溃,因为它从未与new
分配。
void cardHand::addCard(playingCard card) {
theHand[nElems++] = &card;
} // addCard()
在此函数调用中,您传递的是playCard的临时副本并获取其地址。除非你真的知道自己在做什么,否则存储临时地址是不可能的。
相反,将其更改为
/** @param card card to add. Takes ownership. */
void cardHand::addCard(playingCard *card) {
theHand[nElems++] = card;
} // addCard()
在调用代码中,传递一个从playingCard
返回的new playingCard
对象指针。
它仍然存在对象所有权转移的问题,这是双重删除错误或内存泄漏的常见原因。用代码注释明确表达这种转移是一个好习惯。
答案 4 :(得分:1)
所以考虑到其他答案,我的做法是移交引用或指向playingCard
的指针。
关于delete
,一般规则是,你只delete
你new
编辑的内容,即分配内存的人应该对其处置负责。
当然,与任何规则一样,也有例外情况,但这种行为需要在接口的合同中很好地记录。
答案 5 :(得分:1)
经验法则:仅删除您分配的内容(使用new或使用malloc)
因此,你的崩溃。
答案 6 :(得分:1)
它不起作用的原因是你在cardHand::addCard
中按价值传递了你的课程
因此,编译器所做的是在堆栈上构造类实例的临时副本
当它在堆栈中时,一旦addCard
函数返回,它将自动清理
您可以通过将playingCard
实例作为指针传递来解决此问题
但是,正如本文中的其他人所说,建议不要delete
你没有明确new
的内容。