2

I am doing self learning experiments with C++11 shared_pointers to understand how they take ownership of a raw pointer. If they take ownership of the object pointed by raw pointer then the raw pointer should also point to nullptr when the object is deleted.

I have tried a sample code

#include<iostream>
#include<memory>
class X
{
    public:
        X(){std::cout<<"X created\n";}
        virtual ~X(){std::cout<<"X destroyed\n";}
        void show(){std::cout<<"show()\n";}
};

int main()
{
    X *xp = new X;
    {
        std::shared_ptr<X> xs1(xp);
    }

    if(xp)
        xp->show();
    return 0;
}

The output looks like this after g++ -std=c++14

X created
X destroyed
show()

xp should be nullptr but still xp->show() works. Why ?

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
  • xp should not be nullptr, it may point to the memory location already freed. But why it would still successfully call show() is something interesting – user2618142 Jun 07 '19 at 05:05
  • 3
    Undefined Behavior means anything could happen, including seeming to "work". – aschepler Jun 07 '19 at 05:10
  • _`xp` should be `nullptr`_ — No, `xs1` even can't set `xp` to `nullptr`. The constructor of `std::shared_ptr` passes its argument by value, so there is no possibility to reset it. – Daniel Langr Jun 07 '19 at 05:43
  • Don't try to learn C++ by experimenting. – n. m. could be an AI Jun 07 '19 at 07:23
  • related, not dupe: https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope/6445794 – Caleth Jun 07 '19 at 09:49

5 Answers5

2

This is C++, unless you assign nullptr it will always keep the value. The shared_ptr takes a copy of the pointer value and calls delete on it upon destruction of the shared_ptr. This doesn't imply any change to the original raw pointer you used to initialize the shared_ptr.

Also as long no member is used the call to show will probably always work because no read to a freed storage is attempted. As correctly noted this is undefined behavior though.

Reinhold
  • 546
  • 1
  • 3
  • 14
  • 5
    That's only true for modern compilers on default settings. As far as the language is concerned, dereferencing the pointer is undefined behavior, and literally anything could happen. –  Jun 07 '19 at 05:14
0

Another way to prove it is using the value and not pointing to the same object is by changing the value in destructor.

#include<iostream>
#include<memory>
class X
{
    public:
        int a =4;
        X(){std::cout<<"X created\n";}
        virtual ~X(){std::cout<<"X destroyed\n"; a=5;}
        void show(){std::cout<<"show() "<<a<<"\n";}
};

int main()
{
    X *xp = new X;
    {
        std::shared_ptr<X> xs1(xp);
        xs1->show();
    }

    if(xp)
        xp->show();

    return 0;
}

The output is like

X created
show() 4
X destroyed
Before calling show
show() 0
user2618142
  • 1,035
  • 2
  • 18
  • 35
0

If some function inside a C++ class does not access any of its members like in this case for the show() function, then, even after the object is destroyed, if the call is made to such function, then, it works !!! Even if you make the pointer equal to nullptr !!!

It is no surprise, because, we can think C++ compiler generating plain C like functions for class functions and it adds object of the class itself as an argument to such function. As long as the pointer is not accessed, there won't be any issues.

However, in general, it is not a good practice to rely on such behavior.

Also, it is not a good practice to first create an object on heap and then add it to shared_ptr. Instead, create the anonymous object directly as follows:

std::shared_ptr xs1(new X);

And never have any other handle to the pointer of object that is pointed by shared_ptr, because, shared_ptr is supposed to manage the life cycle of it.

Rushikesh
  • 163
  • 8
0

xp should be nullptr

No, you haven't changed the value of xp. You have destroyed the object it pointed to. delete doesn't hunt around memory, looking for values that are equal to what it is passed, to change.

A pointer is not the object it points to. It is a separate object with it's own lifetime. It is up to you, the programmer, to ensure that you don't dereference pointers with invalid values.

Caleth
  • 52,200
  • 2
  • 44
  • 75
-3

As I know, It depent on you build setting.

When you call destruct the object.
You just release your ownership of cells you owner contain this object without re-assign bit 0 to it.
And that cells ready for another program use it.

But your pointer still point to address of that cells. So you still can use this.
It not safe and not sure for use.