Dangling pointer example

Kevin Meredith picture Kevin Meredith · Aug 12, 2010 · Viewed 11.7k times · Source

In the following code, why does s1.printVal causes a dangling pointer error? Isn't the s1 object, i.e. its pointer, still accessible until it's destroyed?

class Sample
{
  public:
    int *ptr;
    Sample(int i)
    {
        ptr = new int(i);
    }

    ~Sample()
    {
        delete ptr;
    }
    void PrintVal()
    {
        cout << "The value is " << *ptr;
    }
};

void SomeFunc(Sample x)
{
    cout << "Say i am in someFunc " << endl;
}

int main()
{
    Sample s1 = 10;
    SomeFunc(s1);
    s1.PrintVal(); // dangling pointer
}

Source

Answer

Nikolai Fetissov picture Nikolai Fetissov · Aug 12, 2010

The problem here is the copy that is done for argument of the SomeFunc(). That copy de-allocates your pointer when destroyed. You need to also implement a copy constructor, and copy assignment operator. See rule of three.

Edit:

Here's "expanded" pseudo-code, i.e. what the compiler does for you in the main() function:

// main
addr0 = grab_stack_space( sizeof( Sample )); // alloc stack space for s1
Sample::ctor( addr0, 10 );                   // call ctor of Sample
addr1 = grab_stack_space( sizeof( Sample )); // alloc stack for argument
Sample::ctor( addr1, addr0 );                // call COPY-ctor of Sample
SomeFunc( addr1 );                           // call SomeFunc
Sample::dtor( addr1 );                       // XXX: destruct the copy
free_stack_space( addr1, sizeof( Sample ));  // free stack taken by copy
Sample::PrintVal( addr0 );                   // call member func on s1
Sample::dtor( addr0 );                       // destruct s1
free_stack_space( addr0, sizeof( Sample ));  // YYY: free stack taken by s1

This is not the exact representation, but a conceptual explanation. It just helps to think in terms of what compiler has to do with your code.

The pointer member of Sample is delete-ed at the step marked with XXX, and then delete-ed again at the step YYY.