开发者

C++ Cleared Memory still accessible

I have a question about why I can access certain pieces of memory, and I think it has to do with the way I understand (or don't understand) how the compiler saves things in memory. This is the sample code I'm working with:

The header file:

#include <iostream>
using namespace std;

class A
{
public:
int value;
A (int newValue = 5)
{
    value = newValue;
    cout << "A()" << endl;
}
~A() { cout <<"~A()" << endl; }
void func1() {cout << "A::func1()" << endl; }

};


class B : public A
{
public:
B() { A::value = 0; cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
virtual void func1 () { cout << "B::func1()" << endl; }

};

class C : public B
{
public:
C() { cout << "C()" << endl; }
~C() { cout << "~C()" << endl; }
virtual void func1() { cout << "C::func1()" << endl; }
};

The .cpp file:

int main()
{
int i;

cout << endl;
A* pA = new A (5);
B* pB = new B;
C* pC = new C;

pA->func1();
pB->func1();
pC->func1();

delete pA;
delete pB;
delete pC;

cout << endl;

    //here is my first question - why don't I get a 开发者_开发百科compiler error here?
    //why does the compiler know what this is? Didn't I delete it?
A* ppA = pC;

    //here is my second question - why does this work?  
    //didn't I clear this memory?
ppA->func1();
B bObject;
B* ppB = &bObject;
ppB->func1();


cin >> i;

    return 0;
}

My questions are right there in the comments - why am I not getting errors on those lines?

If I change the .h file such that func1() is virtual in A as well, I do get an access violation on that line, but still no compile-time errors.

Thanks for any explanations :)


The compiler doesn't track whether a pointer is pointing to a legitimate object. That's a complex analysis that wouldn't even be possible in most common cases. That's why it doesn't generate an error when you assign a deleted pointer to another pointer.

Deleting an object doesn't automatically clear the memory the object used to occupy. It will get overwritten at some indeterminate point in the future, so you should never rely on it staying around. This is called undefined behavior, and one of the hallmarks of undefined behavior is that it might appear to work even when it shouldn't.


The answer to the first question is easy: the instruction is written at compile time. The compiler obviously won't know whether that value has been deleted or not, so it just blindly copies the value of pC over ppA.

The answer to your second question is: it might not work. You have entered scary undefined-behavior-land. Think Alice in Wonderland, without the cat to guide you.

Basically when you call operator delete on a pointer, you're telling the OS that it can overwrite the memory if needed. "If" needed. There's no actual memory erasure going on, just a promise that you won't be using that block of memory anymore.

So when you try to access the virtual table to call func1, the data might still be there. Or not. In which case you get a crash (if you're lucky). But you deserve it, you broke your promise to the OS, so anything goes at this time.

Edit: Note that func1 never actually uses this, so if it wasn't virtual you could have said ((A*)0)->func1() and it would have worked fine.


delete does not remove a name from the code's scope. It is a command to mark that memory as no longer used by your program. That memory may be used by the very next allocation, or never again for the duration of the process's execution.

delete does not zero-out memory for you. You can do that yourself if you need to. What was in that block of memory is not changed until it decides to put a new allocation there. Using a pointer to deleted memory is a Very Bad Idea.


Memory freeing functions like delete, free, HeapFree will not just wipe out the memory. They would just mark them as "unallocated", and further request can be completed by these unallocated memory blocks. The same memory block can be used to server multiple memory allocation calls, or just one call.

It is like deleting (Shift+Deleting) a file - the file wouldn't be actually marked as zeros, it would simply be marked as "free-space". As with file-allocations, multiple free-spaces may be used for one file (and that's why we have "Defragmenters"). But with memory allocations, servicing a large memory block allocation cannot be done by multiple free-memory blocks.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜