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