Chame um destruidor explicitamente em C++

Jinku Hu 12 outubro 2023
Chame um destruidor explicitamente em C++

Este artigo explicará vários métodos de como chamar um destruidor explicitamente em C++.

Use a notação obj.~ClassName() para chamar explicitamente uma função destruidora

Destruidores são funções especiais que são executadas quando um objeto sai do escopo automaticamente ou é excluído por uma chamada explícita do usuário. Observe que essas funções geralmente são utilizadas para liberar os recursos usados ​​por um determinado objeto. Mesmo que um destruidor possa ser chamado explicitamente como uma função de membro, não há necessidade de fazer isso. Na maioria dos casos, onde os membros de dados da classe são alocados dinamicamente, isso pode levar à liberação dupla dos recursos. O último cenário geralmente produz um encerramento anormal do programa.

No exemplo a seguir, demonstramos nossa classe definida chamada - MyClass, que tem dois construtores e um método embutido para recuperar o único valor do membro de dados. O destruidor também é definido e, com os construtores, eles imprimem as mensagens correspondentes ao fluxo cout para facilitar a investigação do comportamento.

Observe que o código de exemplo a seguir imprime duas mensagens do destruidor, uma das quais é disparada pela chamada explícita do usuário e a outra é automaticamente chamada na saída do programa. Embora, se o membro de dados MyClass fosse alocado com o operador new no construtor, este exemplo teria levado a um encerramento anormal do programa - provavelmente sendo uma falha de liberação dupla.

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

Resultado:

Constructor 1 executed

str1: Hello There!

Destructor executed
Destructor executed

Como alternativa, podemos ver que a seguinte versão do código dispara o mesmo número de funções construtor / destruidor, que é essencialmente a ideia por trás deste conceito. Portanto, embora o último exemplo funcione sem nenhuma falha, chamar explicitamente destruidores não é recomendado.

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

Resultado:

Constructor 1 executed
Constructor 2 executed

str2: Hello There!

Destructor executed
Destructor executed

Outro caso a considerar é quando o objeto de classe é alocado com o operador new, e antes da saída do programa, o delete é chamado no mesmo objeto. Observe que a última instrução cout é impressa após a execução da função do descritor, o que significa que o descritor foi chamado quando o operador delete foi chamado.

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

Resultado:

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

Artigo relacionado - C++ Class