在C ++中使用指针的简单代码的行为

时间:2011-02-21 20:45:33

标签: c++ pointers

假设我们有以下代码:

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。我是以正确的方式看待这个吗?

4 个答案:

答案 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)

这是未定义的行为,因为您删除了ab都指向的球体。一旦被删除,它们现在都指向一个无效的球体对象(它甚至不再是一个球体,它只是一个记忆)。 a->setRadius(4.0)可能导致段错误,a->getRadius

要回答您的多项选择问题,e将是正确的。