Expliziter Aufruf eines Destruktors in C++

Jinku Hu 12 Oktober 2023
Expliziter Aufruf eines Destruktors in C++

In diesem Artikel werden verschiedene Methoden zum expliziten Aufrufen eines Destruktors in C++ erläutert.

Verwenden Sie die Notation obj.~ClassName(), um eine Destruktorfunktion explizit aufzurufen

Destruktoren sind spezielle Funktionen, die ausgeführt werden, wenn ein Objekt automatisch den Gültigkeitsbereich verlässt oder durch einen expliziten Aufruf des Benutzers gelöscht wird. Beachten Sie, dass diese Funktionen im Allgemeinen verwendet werden, um die vom angegebenen Objekt verwendeten Ressourcen freizugeben. Obwohl ein Destruktor explizit als Elementfunktion aufgerufen werden kann, ist dies nicht erforderlich. In den meisten Fällen, in denen die Klassendatenelemente dynamisch zugewiesen werden, kann dies zu einer doppelten Freigabe der Ressourcen führen. Das letztere Szenario führt normalerweise zu einer abnormalen Beendigung des Programms.

Im folgenden Beispiel zeigen wir unsere definierte Klasse mit dem Namen MyClass, die zwei Konstruktoren und eine integrierte Methode zum Abrufen des Werts des einzigen Datenelements enthält. Der Destruktor ist ebenfalls definiert, und mit Konstruktoren drucken sie die entsprechenden Nachrichten in den Stream cout, um uns die Untersuchung des Verhaltens zu erleichtern.

Beachten Sie, dass der folgende Beispielcode zwei Destruktornachrichten druckt, von denen eine durch den expliziten Benutzeraufruf ausgelöst wird und die andere beim Beenden des Programms automatisch aufgerufen wird. Wenn das Datenelement MyClass dem Konstruktor new im Konstruktor zugewiesen worden wäre, hätte dieses Beispiel zu einer abnormalen Programmbeendigung geführt - wahrscheinlich ein doppelter Fehler.

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

Ausgabe:

Constructor 1 executed

str1: Hello There!

Destructor executed
Destructor executed

Alternativ können wir sehen, dass die folgende Version des Codes die gleiche Anzahl von Konstruktor / Destruktor-Funktionen auslöst, was im Wesentlichen die Idee hinter diesem Konzept ist. Obwohl das letzte Beispiel fehlerfrei funktioniert, wird das explizite Aufrufen von Destruktoren nicht empfohlen.

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

Ausgabe:

Constructor 1 executed
Constructor 2 executed

str2: Hello There!

Destructor executed
Destructor executed

Ein weiterer zu berücksichtigender Fall ist, wenn das Klassenobjekt dem Operator new zugewiesen wird und vor dem Beenden des Programms das Objekt delete für dasselbe Objekt aufgerufen wird. Beachten Sie, dass die letzte Anweisung cout gedruckt wird, nachdem die Deskriptorfunktion ausgeführt wurde. Dies bedeutet, dass der Deskriptor beim Aufruf des Operators delete aufgerufen wurde.

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

Ausgabe:

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

Verwandter Artikel - C++ Class