views:

146

answers:

4

I am fooling around with C++ and const references and am confused why this code works:

#include <iostream>

class A {
public:
    A() : a_(50) {}
    const int& getA() const { return a_; }
private:
    const int a_;
};

int main(int argc, char* argv[])
{
    A* a = new A();
    const int& var = a->getA();
    std::cout << var << std::endl;
    delete a;
    std::cout << var << std::endl;
}

Result:

50
50

Here are my thoughts:

var stores a reference to a_.
when a is deleted, a_ should also be deleted.
when var is accessed again, it no longer contains a valid reference and a segmentation fault should occur.

Why does this work? I do not believe I make a temporary copy.

+11  A: 

The moment you deleted a, accessing var became your door into undefined behavior land.

It's "working" by chance. The space where var was one referring to is no longer yours, but you got away with accessing it, this time. It could have resulted in a segmentation fault, returned a number other than 50, or reformatted your hard drive.

Remember, seeming to work is one possible way undefined behavior can manifest itself.

GMan
This was my best guess - it works in this case, but it has undefined behavior. It is definitely not guaranteed to work and is very dangerous.
devillighter
Whats worse - one of those bugs that will behave differently in debug/release and on single/dual core CPUs
Martin Beckett
+3  A: 

Deleting an object does not clear the memory. The value will still be there until the memory is used for something else. So it may work for a while....

Some C++ implementations have a "debug mode" that sets a particular value to all deleted memory to detect bugs like this.

Arve
+2  A: 

When you delete a you are freeing the memory and allowing a latter new to override it. Until then all the variables inside your deleted object are still in memory, but may be overridden at any time.

bramp
+1  A: 

This is quite tricky because of the const keyword.

True, you could be reading uninitialized memory in this case. Some thoughts on that:

  1. You're not using debug mode: this is generally not a good idea as long as the code hasn't been tested, but it leaves two options:
    • The release mode memory manager does not overwrite the memory, so you acces the last known address, which still works by chance
    • OR The whole operation is completely optimized away because the compiler knows you didn't change the value and it couldn't change from the outside (though that might not be true due to the limitations of const correctness in C++)
  2. You are in debug mode, but have optimizations activated, so the same argument applies
  3. The contents of _a, since marked const are not heap-allocated nor stack allocated but reside in the DATA section of the application, so the reference might indeed be still valid, not only by chance. [EDIT]: This can only be true for static const variables.

You might consider writing a custom memory manager or research on the debug mode behaviour of your compiler, because this is very, very important. Visual Studio will set variables to 0xCDCDCDCD, for example. You will also find funny values such as 0xDEADC0DE at the end of arrays.

mnemosyn
Regarding (3), the only way that `_a` could be in "the DATA section" would be if the compiler performed extensive static analysis and determined there was only ever 1 instance of `A`, in which case the entire object would be there. A `const` member still occupies space in each instance of an object.
j_random_hacker
very true... Edited my answer accordingly. Thanks for correcting me.
mnemosyn
Yeah, I wondered if you were thinking of static const. +1.
j_random_hacker