开发者

Behavior of simple code with pointers in C++

Suppose we have the following code:

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;

What will be the outcome:

(a) 4.0
(b) 3.0
(c) A segmentation fault.
(d) 开发者_Go百科Compiler error.
(e) The behavior cannot be predicted.

I dont think you'll need to see the sphere class, as its pretty obvious whats going on. Now, when we set b=a, this means bis pointing to a. Then we delete b, which means we delete what b was pointing to, and that means that a is now no longer pointing to anything. So when we try to say a->setRadius, we cant. And so I think thats a seg fault. Am I looking at this the right way?


It's undefined behavior. It might segfault, or it might give birth to a litter of kittens. Either (and any number of other possibilities) would be conforming behavior. A very likely outcome is that it will silently corrupt your heap, with baffling consequences later on.


Up to delete b; everything is ok. The next line (a->setRadius(4.0);) will trigger an undefined behaviour, because you are accessing a deleted object. The problem is that 90% of the times it will work (yes, this is a problem, because the other 10% of the times it will crash and you will lose the night finding why!)

Why this? This happens because many implementations of operator new and delete don't "ask" the memory to the OS every time they are called. They ask a big block of it and then use it a little at a time. When you delete your object, the memory is only "marked" as free, and not freed. So when you access a deallocated object, you are accessing memory that (probably) is still allocated to your process, but that you shouldn't use. In the middle some other part of your program could have allocated it and modified it, or simply the delete operator could have seen that there was so much memory "marked as free" and decided to return it to the OS, triggering a SEGFAULT if you try to access it. A "debug" version of the delete could fill it with a pattern or zero it, so that if you watch it it's more evident that it's in use or free... There are many options.

A note: I have simplified the handling of memory by new and delete. "Normally" there are some more levels of indirection. But they are irrelevant to the discussion.

On some implementations of new/delete/malloc/free on debug builds the memory, instead of being zeroed, is filled with 0xcc or 0xcdcd. This is for two reasons. If I remember correctly one is that 0xcc is the Intel instruction for the INT 3 breakpoint (and 0xcdcd is a multiple or something similar). The other is that if you watch it in a debugger, the pattern is quite obvious to see, while an "all 0x00" pattern could be more difficult to distinguish.


With delete b;, you are deallocating the memory location which both pointers a,b were earlier pointing to. So, a->setRadius(4.0); behaviour is undefined. By undefined means it may work correctly as you expected or can result a segmentation fault or anything can happen.

Since a is a dangling pointer, a->getRadius(); would also result undefined behaviour.


It's undefined behavior because you delete the sphere with which a and b are both pointing. Once deleted, they are now both pointing to an invalid sphere object (it's not even a sphere anymore, its just memory). a->setRadius(4.0) has the potential of causing a seg fault, along with a->getRadius.

To answer your multiple choice question, e would be correct.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜