C++ life cycle examples of destructors and variables

  • 2020-05-24 05:56:34
  • OfStack

C++ life cycle examples of destructors and variables

This article introduces the destructor function, which is my reading notes. I hope it is short but comprehensive enough for review. If you have some C++ information that you don't remember, it will help you remember it quickly.

The name of the destructor (destructor) is the same as the class name, but preceded by a "~". Destructors have no arguments or return values, and of course cannot be overloaded.

When to call the destructor

It is well known that destructors are called automatically when an object dies, but the implication is that both the parameter object of the function and the object as the return value of the function also cause the destructor to be called when it dies.


#include<iostream>
using namespace std;
class CNum {
public:
  int num;
  ~CNum() { cout << "destructor" << endl; }
  CNum() { num = 0; cout << "constractor CNum()" << endl; }
  CNum(CNum & n) { num = n.num; cout << "constractor CNum(CNum & n)" << endl; }
};

CNum fun(CNum n) {
  cout << "fun()start" << endl;
  n.num = 3;                // The modification here only modifies the parameter, and has no effect on the argument 
  return n;
}

int main() {
  CNum n1;
  n1 = fun(n1);
  return 0;
}

Operation results:

constractor CNum()
constractor CNum(CNum & n)// n
fun ()
constractor CNum(CNum & n)// is constructed as a temporary object for the return value
The return value of destructor//fun is a temporary object with a lifetime of only one statement
destructor// leaves fun(), n dies
The local variable n1 dies when destructor//main ends

Please press any key to continue..

Calling a function by passing a reference instead of passing the object directly saves many unnecessary function calls, especially if the function is called frequently.

Virtual destructor

Destructors can be virtual, but constructors can't. Think 1: the constructor can be overloaded, but the destructor can't. The pair are even.

In general, if a class defines a virtual function, it is best to define the destructor as a virtual function as well. This is recommended because it is easy to have hidden bug. Look at 1 piece of code:


class CShape {
public: ~CShape() {/* Do nothing */} 
};

class CCircle :public CShape {
  public:
  CCircle() {/* Memory is allocated here */}
  ~CCircle() {/* This frees up memory */ }
};

int main() {
  CShape * ptrShape = new CCircle();
  delete ptrShape;
  return 0;
}

So, delete ptrShape; What destructor is being executed? Instead of the ~CCircle() that we wanted to call, we called the ~CShape() that did nothing, and the memory leaked. The way to avoid this is to define the destructor as a virtual function. virtual ~CShape(){/* do nothing */}; . As long as the destructor of the base class is virtual, the destructor of the derived class will become virtual destructor whether or not it is declared with the "virtule" keyword.

The lifetime of the variable

1) the life cycle of all variables is from the beginning of the program to the end, and it is defined first, generated first, and died later. The constructor of the global variable is called before it enters main() and dies after main() is pushed.

2) the life cycle of the temporary object shall not be longer than the execution time of the statement. Type conversion statements, return statements, and so on May generate temporary variables.

3) the lifetime of local variables is from the beginning of the definition to the end of the most recent "}"

4) static local variables are generated when the definition statement is executed for the first time, and die before the global variables die at the end of the program.

Thank you for reading, I hope to help you, thank you for your support of this site!


Related articles: