How to Call a Destructor Explicitly in C++

Jinku Hu Feb 02, 2024
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
Author: 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

Related Article - C++ Class