我正在为学校做一个项目。 它模拟学生从自动售货机购买苏打水。 有一个名为Card的类,它是Student类中的成员。 也就是说,
每个学生都有一张卡片,这是有意义的。
class Student {
public:
Student( Office &cardOffice );
~Student();
bool action();
private:
Office* studentOffice; // stores cardoffice.
Card* card; // stores card
};
学生卡是通过调用studentOffice.create()函数创建的。该函数返回一张卡片。
Card* Office::create( int id, int money ) {
Card* card = new Card();
card->id = id;
card->amount = money;
return card;
}
学生在VendingMachine类中调用一个名为action()的函数来购买食物。 VendingMachine中的buy函数返回VendingMachine类中Status enum的类型枚举。
有一个prng,从0到9生成一个随机数。作业说,学生卡被摧毁的概率为十分之一。并且他/她将在下次调用student.action()时获得一个新的。
VendingMachine::Status VendingMachine::buy(Card* &card)
{
if(prng(9) == 0) // generates number from 0-9
{
delete card;
}
return status;
}
最初,我正在考虑检查学生的action()例程以查看该卡是否为NULL(如果已删除),并在发生这种情况时创建一个新卡。但是,我知道代码到达删除卡部分,但在检查卡是否为NULL时失败。所以这必须意味着卡不是空的,这意味着删除不起作用。
但我也注意到传入的卡是
类型Card* &card
我当时正在考虑使用带有“this”指针的调用,因为我知道学生调用了这个例程,“this”将指向根据以下内容调用它的对象:
它指向调用成员函数的对象。 来自http://msdn.microsoft.com/en-us/library/y0dddwwd(v=vs.80).aspx
但是,如果我这样做:
if(prng(9) == 0)
{
delete this->card;
}
运行makefile时出现此错误:
错误:类VendingMachine没有名为card的成员
这是真的,但事实并非如此。编译器是否假设VendingMachine会调用此方法?因为学生的确如此。
也许我应该在每台自动售货机上添加一名学生,然后从该会员中删除该卡?我强烈不愿意这样做,因为有多个学生,这意味着如果他们被分配到这台自动售货机,我需要将它们全部存储起来。虽然,如果归结为它,我可以这样做。
如果发生了删除卡,但该卡不是NULL,那么当我删除该卡时究竟发生了什么?
如何删除该卡?
谢谢!
编辑:应用更改后,代码现在是:
if(prng(9) == 0)
{
cout << "Destroying card" << endl;
delete card;
card = NULL;
cout << "Card Destroyed" << endl;
}
不幸的是,我遇到了段错误,这可能是因为我正在访问一张不存在的被破坏的卡片。因为显示销毁卡和销毁卡,
但是我在这次电话会议中的cout没有出现:
if(card == NULL)
{
cout << "CARD DESTROYEDADJIWJDOQIODJWDIOJWQODWODIQODJWJOWDW" << endl;
card = studentOffice->create(id, 5);
}
显然卡仍然不是NULL?这很奇怪。
EDIT2:我想我知道问题所在,以及为什么会出现段错误。现在正在努力。
EDIT3:通过重新排列卡被销毁时使用卡的电话的顺序来解决。
答案 0 :(得分:3)
在方法buy
中,您应该删除指针并将其设置为NULL
(delete
不会自动将指针设置为NULL
):
VendingMachine::Status VendingMachine::buy(Card* &card)
{
if(prng(9) == 0) // generates number from 0-9
{
delete card;
card = NULL;
}
return status;
}
这就是指针通过引用传递的原因(因此您可以将NULL
分配给原始指针而不是它的副本。)
除此之外,this->card
无法编译,因为card
属于类Student
,而不属于VendingMachine
。从VendingMachine
的角度来看,它只是方法buy
中的一个参数。
答案 1 :(得分:2)
当您致电delete
时,没有任何内容可以说您将其调用的指针设置为NULL
。如果要在删除后确保它为NULL,则应在删除后自行完成。
答案 2 :(得分:1)
除了@ betabandido的答案之外,您始终可以在宏中定义删除方法来为您执行此操作。
#define DELETE(ptr) ( delete ptr; ptr = NULL;)
虽然不可否认,这几乎总是一个坏主意,特别是当你在学校时,你应该养成在删除指针后将指针设置回NULL的习惯。
此外,这可能会导致您产生错误的安全感:
void MethodDeleteThis(void* item)
{
delete item;
item = NULL;
}
没有真正解决问题,因为item是传递指针的COPY。因此,虽然delete可能释放了item指向的对象,但将指针设置为NULL不会将传递给该方法的指针的值更改为NULL。解决这个问题的唯一方法是采用双指针或通过引用传递指针 - 这通常看起来很奇怪而且不合适。我见过gobject和gstreamer这样做。
我注意到,许多库总是在有任何分配或释放时返回指针,以便您可以更可靠地检索和测试值。
答案 3 :(得分:1)
正如其他人所指出的,每当你delete
指针时,你也应该立即将它设置为NULL
。不要使用宏,养成这样做的习惯。
现在,试着戴上我的最佳实践帽子:
我总是发现在做这类事情时传递双指针更有用,而不是通过引用传递指针:
VendingMachine::Status VendingMachine::buy(Card** card) {
// ...
if (NULL == *card) {
delete *card;
*card = NULL;
}
这迫使你在代码中稍微区别对待指针,但好处是你操作指针更明显,它消除了方法调用中的歧义:
vend.buy(card); // Pointer reference
vend.buy(&card); // Pointer to pointer
通过第二次调用,您只需通过查看该方法即可修改card
的值。