2

Why is the output of the following code different depending on whether I use a shared_ptr or unique_ptr? The output of shared_ptr makes sense, because the object is fully destructed, while in the case of unique_ptr, only the base class part is destructed. I thought that when I use a smart pointer, I don't have to make the destructor virtual for the full object to be destructed successfully.

#include <iostream>
#include <memory>
using namespace std;
class base
{
  public:
  base(){cout <<"base class constructor " <<endl;}
  ~base(){ cout <<"base class Destructor "<<endl;}
};
class derv: public base
{
  public:
  derv(){cout <<"derv class constructor " <<endl;}
  ~derv(){ cout <<"derv class Destructor "<<endl;}
};

When the above code is called by shared_ptr, the full object (base and derv) is destructed.

int main()
{
  shared_ptr<base> p1 (new derv);
}
Output:
 base class constructor                                                                              
 derv class constructor                                                                              
 derv class Destructor                                                                                    
 base class Destructor

When called by unique_ptr, only the base part is destructed but not the derv part.

int main()
{
  unique_ptr<base> p1 (new derv);
}
Output:
 base class constructor                                                                              
 derv class constructor
 base class destructor                                                                         
Justin
  • 24,288
  • 12
  • 92
  • 142
Alok
  • 1,997
  • 2
  • 18
  • 30
  • 1
    Very related: https://stackoverflow.com/q/22124981/1896169 , https://stackoverflow.com/q/22959557/1896169 – Justin Mar 12 '18 at 04:30
  • Also related: https://stackoverflow.com/q/20802810/1896169 , https://stackoverflow.com/q/3899790/1896169 , https://stackoverflow.com/q/30115809/1896169 – Justin Mar 12 '18 at 04:36
  • 1
    You should have a virtual desctructor in the base to work properly. But without seeing if the pointer code uses base or derived pointers, it's not clear in detail how you got this behaviour. – Zólyomi István Mar 12 '18 at 04:39
  • @ZólyomiIstván I don't know what you mean by "without seeing if the pointer code uses base or derived pointers". The OP gave clear examples. – Justin Mar 12 '18 at 04:41
  • @Justin - It's not a duplicate. This question is much more explicitly asking for rationale. The other one has an answer that basically says "Because the standard says so.". There is a reason the standard says so. – Omnifarious Mar 12 '18 at 07:54

1 Answers1

4

I assume that you know the mechanics of why this is. If you need to get a refresher, go see Why unique-ptr doesn't check base class to virtual destructible? . That question has an answer that gives the mechanics in detail.

I assume your question is, why did the standard do it this way? And the answer is simple. With a shared_ptr there is a clear place to put the information about which deleter to use, and that's the same place you put the reference count and probably the real pointer to the object.

That latter is a time/space tradeoff. It depends on whether or not your shared_ptr object has a pointer to the reference count and a pointer to the object, or just has a pointer to a 'handle' that contains the object pointer and all the other needed information. What do you want, a smaller pointer, or a pointer that doesn't have to do an extra level of indirection to get at the pointer to object?

With unique_ptr there is no place to put this information. You could put it in the unique_ptr object itself, but then that object would be 2-3 times as big as a normal pointer, and that's not what the standard was aiming for at all. There is supposed to be no rational reason anybody could possibly have for not using unique_ptr, and so it must perform in all ways at least as well as a regular pointer.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194