Destrucción virtual usando shared_ptr en C++

Requisito previo: shared_ptr , Destructor virtual

Como sabemos, eliminar un objeto de clase derivado usando un puntero a una clase base que tiene un destructor no virtual da como resultado un comportamiento indefinido. Por lo tanto, hacemos que el destructor de clase base sea virtual para que los objetos polimórficos se eliminen correctamente en el orden correcto (es decir, en el orden inverso al de su creación).

También se puede lograr un comportamiento similar mediante el uso de shared_ptr sin tener el destructor de clase base virtual. Echemos un vistazo al siguiente código:

// Program to show the 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 << "Destructing 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
}

Producción:

Constructing Base
Constructing Derived
Destructing Derived
Destructing Base

Como se muestra en el resultado anterior, ya no es necesario hacer que el destructor de la clase Base sea virtual, mientras se logra el comportamiento del destructor virtual al mismo tiempo.

¿Cómo shared_ptr logra este comportamiento mágico?

shared_ptr recuerda el tipo de puntero utilizado durante la construcción. Por ejemplo,

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*. 

Cuando se destruye shared_ptr, llama a delete en el puntero almacenado. Naturalmente, con destructores no virtuales, para Base* llamará Base::~Base y para Derived* llamará Derived::~Derived.
Puntos importantes :

  • Este comportamiento se logra solo con shared_ptr .
  • Este comportamiento no se logra mediante el uso de unique_ptr.
  • Todas las clases en STL no tienen destructor virtual, así que tenga cuidado si hereda de ellas. Si desea heredar, puede usar shared_ptr en ese caso para aplicar la destrucción inteligente.

Condición excepcional: Inicialización desde la base

Considere el siguiente ejemplo:

// 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 };
}

Producción:

Constructing Base
Constructing Derived
Destructing Base

Aquí, si shared_ptr se inicializa desde Base* (aquí ‘p’), entonces este comportamiento mágico de destrucción inteligente no se logrará ya que llamará a Base::~Base() y no a Derived::~Derived(). shared_ptr no podrá averiguar el tipo exacto del objeto al que apunta ‘p’. Entonces, en este caso, la magia no sucede.

Artículos relacionados:

Este artículo es una contribución de Arnav Srivastava . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *