How to Call a Destructor Explicitly in C++
This article will explain several methods of how to call a destructor explicitly in C++.
Use the obj.~ClassName()
Notation to Explicitly Call a Destructor Function
Destructors are special functions that get executed when an object goes out of scope automatically or is deleted by an explicit call by the user. Note that these functions are generally utilized to free up the resources used by the given object. Even though a destructor can be called explicitly as a member function, there’s no need to do this. In most cases, where the class data members are dynamically allocated, it can lead to double freeing of the resources. The latter scenario usually yields an abnormal termination of the program.
In the following example, we demonstrate our defined class called - MyClass
, which has two constructors and one built-in method to retrieve the only data member’s value. The destructor is also defined, and with constructors, they print the corresponding messages to the cout
stream to make it easier for us to investigate the behavior.
Notice that the following example code prints two destructor messages, one of which is triggered by the explicit user call, and the other is automatically called on program exit. Although, if the MyClass
data member was allocated with the new
operator in the constructor, this example would have led to an abnormal program termination - likely being a double-free fault.
#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;
}
Output:
Constructor 1 executed
str1: Hello There!
Destructor executed
Destructor executed
Alternatively, we can see that the following version of the code triggers the same number of constructor/destructor functions, which is essentially the idea behind this concept. So, even though the last example works without any fault, explicitly calling destructors is not recommended.
#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;
}
Output:
Constructor 1 executed
Constructor 2 executed
str2: Hello There!
Destructor executed
Destructor executed
Another case to consider is when the class object is allocated with the new
operator, and before the program exit, the delete
is called on the same object. Note that the last cout
statement gets printed after the descriptor function executes, meaning that the descriptor was invoked when the delete
operator was called.
#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;
}
Output:
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