Virtual destruction using shared_ptr in C++

Prerequisite: shared_ptr, Virtual Destructor

As we know that, deleting a derived class object using a pointer to a base class that has a non-virtual destructor results in undefined behavior. Thus, we make the base class destructor virtual so that the polymorphic objects are being deleted properly in the correct order (i.e. the reverse order of their creation).

Similar behavior can also be achieved by using a shared_ptr without having the Base class destructor virtual. Let us have a look on the following code:

filter_none

edit
close

play_arrow

link
brightness_4
code

// Program to show order of destruction of objects using
// shared_ptr
#include <iostream>
#include <memory>
using namespace std;
  
class Base {
public:
    Base()
    {
        cout << "Constructing Base" << endl;
    }
    ~Base()
    {
        cout << "Destructing Base" << endl;
    }
};
  
class Derived : public Base {
public:
    Derived()
    {
        cout << "Constructing Derived" << endl;
    }
    ~Derived()
    {
        cout << "Constructing Derived" << endl;
    }
};
  
int main()
{
    std::shared_ptr<Base> sp{ new Derived };
  
    // make_shared can also be used to create sp.
    // std::shared_ptr<Base> sp{std::make_shared<Derived>()};
    // Use sp
}

chevron_right


Output:

Constructing Base
Constructing Derived
Destructing Derived
Destructing Base

As shown in the above output, there is no need to make the destructor of the Base class virtual anymore, while achieving the virtual destructor behavior at the same time.



How shared_ptr achieves this magical behavior?

The shared_ptr remembers the pointer type used during construction. For example,

If you say shared_ptr{ new Derived {} },
then shared_ptr will internally store a Derived*. 
If you say shared_ptr{ new Base {} }, 
then it stores a Base*. 

When the shared_ptr is destructed, it calls delete on the stored pointer. Naturally, with non-virtual destructors, for Base* it will call Base::~Base and for Derived* it will call Derived::~Derived.
Important points :

  • This behavior is achieved by shared_ptr only.
  • This behavior is not achieved by using unique_ptr.
  • All the classes in STL do not have virtual destructor, so be careful if you inherit from them. If you want to inherit, you can use shared_ptr in that case to have the smart destruction applied.

Exceptional Condition : Initializing from Base

Consider the following example:

filter_none

edit
close

play_arrow

link
brightness_4
code

// Program to show exception to this behavior while using
// shared_ptr
#include <iostream>
#include <memory>
using namespace std;
  
class Base {
public:
    Base()
    {
        cout << "Constructing Base" << endl;
    }
    ~Base()
    {
        cout << "Destructing Base" << endl;
    }
};
  
class Derived : public Base {
public:
    Derived()
    {
        cout << "Constructing Derived" << endl;
    }
    ~Derived()
    {
        cout << "Constructing Derived" << endl;
    }
};
  
int main()
{
    Base* p = new Derived{};
    std::shared_ptr<Base> sp{ p };
}

chevron_right


Output:

Constructing Base
Constructing Derived
Destructing Base

Here, if the shared_ptr is initialised from Base* (here ‘p’), then this magical behavior of smart destruction will not be achieved as this will call Base::~Base() and not Derived::~Derived(). The shared_ptr will not able to find out the exact type of the object which is being pointed to by ‘p’. So in this case, the magic does not happen.

Related Articles:

This article is contributed by Arnav Srivastava. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.



My Personal Notes arrow_drop_up


Article Tags :
Practice Tags :


1


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.