Llamar a un destructor explícitamente en C++

Jinku Hu 12 octubre 2023
Llamar a un destructor explícitamente en C++

Este artículo explicará varios métodos de cómo llamar a un destructor explícitamente en C++.

Utilice la notación obj.~ClassName() para llamar explícitamente a una función destructora

Los destructores son funciones especiales que se ejecutan cuando un objeto sale del alcance automáticamente o es eliminado por una llamada explícita por parte del usuario. Tenga en cuenta que estas funciones se utilizan generalmente para liberar los recursos utilizados por el objeto dado. Aunque se puede llamar explícitamente a un destructor como función miembro, no es necesario hacer esto. En la mayoría de los casos, cuando los miembros de datos de la clase se asignan dinámicamente, puede conducir a una doble liberación de los recursos. El último escenario suele producir una terminación anormal del programa.

En el siguiente ejemplo, demostramos nuestra clase definida llamada - MyClass, que tiene dos constructores y un método incorporado para recuperar el valor del único miembro de datos. El destructor también está definido, y con los constructores, imprimen los mensajes correspondientes al flujo cout para facilitarnos la investigación del comportamiento.

Observe que el siguiente código de ejemplo imprime dos mensajes de destructor, uno de los cuales se activa por la llamada explícita del usuario y el otro se llama automáticamente al salir del programa. Aunque, si el miembro de datos MyClass se asignó con el operador new en el constructor, este ejemplo habría llevado a una terminación anormal del programa, probablemente una falla sin doble.

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

class MyClass {
 public:
  explicit MyClass(string s) : str(std::move(s)) {
    cout << "Constructor 1 executed\n";
  }

  MyClass(const MyClass& s) : str(string(s.str)) {
    cout << "Constructor 2 executed\n";
  }

  ~MyClass() { cout << "Destructor executed\n"; }

  string& getString() { return str; };

 private:
  string str;
};

int main() {
  MyClass str1("Hello There! ");

  cout << endl;
  cout << "str1: " << str1.getString() << endl;
  cout << endl;

  str1.~MyClass();

  return EXIT_SUCCESS;
}

Producción :

Constructor 1 executed

str1: Hello There!

Destructor executed
Destructor executed

Alternativamente, podemos ver que la siguiente versión del código activa el mismo número de funciones de constructor / destructor, que es esencialmente la idea detrás de este concepto. Por lo tanto, aunque el último ejemplo funciona sin fallas, no se recomienda llamar explícitamente a los destructores.

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

class MyClass {
 public:
  explicit MyClass(string s) : str(std::move(s)) {
    cout << "Constructor 1 executed\n";
  }

  MyClass(const MyClass& s) : str(string(s.str)) {
    cout << "Constructor 2 executed\n";
  }

  ~MyClass() { cout << "Destructor executed\n"; }

  string& getString() { return str; };

 private:
  string str;
};

int main() {
  MyClass str1("Hello There! ");
  MyClass str2(str1);

  cout << endl;
  cout << "str2: " << str2.getString() << endl;
  cout << endl;

  return EXIT_SUCCESS;
}

Producción :

Constructor 1 executed
Constructor 2 executed

str2: Hello There!

Destructor executed
Destructor executed

Otro caso a considerar es cuando el objeto de clase se asigna con el operador new, y antes de salir del programa, se llama a delete en el mismo objeto. Tenga en cuenta que la última instrucción cout se imprime después de que se ejecuta la función de descriptor, lo que significa que el descriptor fue invocado cuando se llamó al operador delete.

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

class MyClass {
 public:
  explicit MyClass(string s) : str(std::move(s)) {
    cout << "Constructor 1 executed\n";
  }

  MyClass(const MyClass& s) : str(string(s.str)) {
    cout << "Constructor 2 executed\n";
  }

  ~MyClass() { cout << "Destructor executed\n"; }

  string& getString() { return str; };
  string* getStringAddr() { return &str; };

 private:
  string str;
};

int main() {
  auto* str4 = new MyClass("Hello There! ");

  cout << endl;
  cout << "str4: " << str4->getString() << endl;
  cout << endl;

  delete str4;
  cout << "exiting" << endl;

  return EXIT_SUCCESS;
}

Producción :

Constructor 1 executed

str4: Hello There!

Destructor executed
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Artículo relacionado - C++ Class