假设我们有以下代码:
sphere * a, * b;
a = new sphere(1.0);
b = a;
b->setRadius(2.0);
delete b;
a->setRadius(4.0);
sphere * c = new sphere(5.0);
b = new sphere(3.0);
cout << a->getRadius() << endl;
结果会是什么:
(a) 4.0
(b) 3.0
(c) A segmentation fault.
(d) Compiler error.
(e) The behavior cannot be predicted.
我认为你不需要看球体类,因为它很明显是什么。现在,当我们设置b=a
时,这意味着b
指向a
。然后我们delete b
,这意味着我们删除b
指向的内容,这意味着a
现在不再指向任何内容。所以当我们试着说a->setRadius
时,我们不能。所以我认为那是seg fault
。我是以正确的方式看待这个吗?
答案 0 :(得分:14)
这是未定义的行为。它可能是段错误,或者它可能会产生一窝小猫。 (以及任何其他可能性)将是符合行为的。一个非常可能的结果是,它会在以后悄悄地破坏你的堆,带来令人费解的后果。
答案 1 :(得分:2)
最多delete b;
一切正常。下一行(a->setRadius(4.0);
)将触发未定义的行为,因为您正在访问已删除的对象。问题是90%的时间它会起作用(是的,这是一个问题,因为其他10%的时间会崩溃,你会失去夜晚找到原因!)
为什么这样?发生这种情况是因为operator new和delete的许多实现在每次调用时都不会向OS“询问”内存。他们问了一大块,然后一次使用它。删除对象时,内存仅“标记”为空闲,不会被释放。因此,当您访问一个已释放的对象时,您正在访问(可能)仍然分配给您的进程的内存,但您不应该使用它。在中间你的程序的其他部分可以分配并修改它,或者只是删除操作符可以看到有太多的内存“标记为免费”并决定将其返回到操作系统,如果你触发了SEGFAULT试着访问它。删除的“调试”版本可以用一个模式填充它或者将它填充为零,这样如果你看它就更明显它正在使用或免费......有很多选择。
注意:我已经通过new和delete简化了内存处理。 “通常”有一些更多层次的间接。但它们与讨论无关。
在调试的new / delete / malloc / free的一些实现上构建内存而不是归零,用0xcc或0xcdcd填充。这有两个原因。如果我没记错的话,一个是0xcc是INT 3断点的Intel指令(0xcdcd是多个或类似的东西)。另一个是如果你在调试器中观察它,那么模式很明显,而“全0x00”模式可能更难以区分。
答案 2 :(得分:1)
使用delete b;
,您将释放两个指针a,b
之前指向的内存位置。因此,a->setRadius(4.0);
行为未定义。通过未定义意味着它可以按预期正常工作,或者可能导致分段错误或任何可能发生的事情。
由于a
是一个悬空指针,a->getRadius();
也会导致未定义的行为。
答案 3 :(得分:1)
这是未定义的行为,因为您删除了a
和b
都指向的球体。一旦被删除,它们现在都指向一个无效的球体对象(它甚至不再是一个球体,它只是一个记忆)。 a->setRadius(4.0)
可能导致段错误,a->getRadius
。
要回答您的多项选择问题,e
将是正确的。