Details on destructors in C++ programming

  • 2020-05-05 11:30:19
  • OfStack

C++ destructor

Similarly, when an object is created, the system automatically calls a constructor to initialize it, and when an object is destroyed, the system automatically calls a function to clean it up (for example, to reclaim the various resources consumed when the object is created). This function is called a destructor.

The destructor (Destructor) is also a special member function that returns no value, does not need to be called by the user, and is executed automatically when the object is destroyed. Unlike constructors, the destructor's name is preceded by a "~" symbol.

Note: destructors have no arguments and cannot be overloaded, so a class can only have one destructor. If the user has no definition, the compiler generates it automatically.

Example destructor:


#include <iostream>
using namespace std;
class Student{
private:
  char *name;
  int age;
  float score;
public:
  // The constructor 
  Student(char *, int, float);
  // The destructor 
  ~Student();
  // Ordinary member function 
  void say();
};
Student::Student(char *name1, int age1, float score1):name(name1), age(age1), score(score1){}
Student::~Student(){
  cout<<name<<" goodbye "<<endl;
}
void Student::say(){
  cout<<name<<" The age is  "<<age<<" , the result is  "<<score<<endl;
}
int main(){
  Student stu1(" Xiao Ming ", 15, 90.5f);
  stu1.say();
  
  Student stu2(" Li lei ", 16, 95);
  stu2.say();
  
  Student stu3(" Wang Shuang ", 16, 80.5f);
  stu3.say();
  cout<<"main  The function is about to run out "<<endl;
  
  return 0;
}

Results:


 Xiao Ming's age is  15 , the result is  90.5
 Li lei's age is  16 , the result is  95
 Wang shuang's age is  16 , the result is  80.5
main  The function is about to run out 
 Wang Shuang goodbye 
 Li lei goodbye 
 Xiao Ming goodbye 

As you can see, the destructor is executed before the main function runs, and the sequence of calls is exactly the opposite of the constructor. For the sake of memory, we can think of it as a stack, first in, then out.
Why is the execution order of the destructor inverse?
The destructor is executed before the object is destroyed. To know when a destructor is called, you need to know when an object is destroyed.

An object can be thought of as a variable defined by a data type such as a class, and it has many of the same properties as a normal variable, such as scope, lifecycle, and so on. It can be inferred that the destruction time of a variable like an object is the same as that of a normal variable.

In summary, there are several cases:
1) if an object is defined in a function (auto local variable), when the function runs, the object is destroyed, and the destructor is automatically executed before the object is destroyed.

2) the static local object is not destroyed at the end of the function call, so the destructor is not called, and the destructor of the static local object is called only at the end of the program (such as the main function or the exit function).

3) if a global object is defined, the destructor of the global object is called only at the end of the program.

4) if an object is created dynamically with the new operator, when the object is released with the delete operator, the destructor of the object is first called.

Note: the purpose of the destructor is not to delete the object, but to clean up the memory that the object occupies before undoing it so that it can be allocated to the new object.

C++ the order in which the constructor and destructor are called
When using constructors and destructors, you need to pay special attention to the timing and order in which they are invoked. In general, the destructor is called in the reverse order of the constructor: the constructor that is called first is the one whose destructor (in the same object) is called last, and the constructor that is called last is the one whose destructor is called first. As shown in example 9.5, the destructor for stud2 is executed, followed by the destructor for stu1.

It can be abbreviated as: post-destruct constructed first, post-destruct constructed first, which is equivalent to a stack, first in, then out.

However, this principle is not always followed. Objects can be defined in different scopes and can have different types of storage. These affect the timing of constructor and destructor calls.

Here's a summary of when constructors and destructors are called:
1) an object defined in the global scope (that is, an object defined outside of all functions) whose constructor is called before all functions in the file (including the main functions) are executed. But if there are multiple files in a program, and global objects are defined in different files, the execution order of the constructors for those objects is uncertain. The destructor is called when the main function is executed or when the exit function is called (at which point the program terminates).

2) if a local automatic object is defined (for example, an object is defined in a function), its constructor is called when the object is created. If the function is called multiple times, the constructor is called each time the object is created. The destructor is called when the function call ends and the object is released.

3) if the static (static) local object is defined in the function, then the constructor is called only once when the program first calls this function to create the object, and the object is not released at the end of the call, so the destructor is not called, and only when the main function ends or the exit function ends the program is called.

For example, two objects are defined in a function:


void fn(){
  Student stud1; // Define an automatic local object 
  static Student stud2; // Define a static local object 
}


When the fn function is called, the constructor of stud1 is called, and then the constructor of stud2 is called. At the end of the fn call, stud1 is released (because it is an automatic local object), so the destructor of stud1 is called. stud2 is a static local object that is not released at the end of the fn call, so the destructor of stud2 is not called. The destructor of stud2 is not called until stud2 is released at the end of the program. You can see that stud2 calls the constructor later, but not its destructor first. The reason is that the two objects have different storage categories and different lifecycles.


Related articles: