Since the delete operator frees up memory, why do I need a destructor?

From the C ++ FAQ: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9

Remember: delete p performs two functions: calls the destructor and frees memory.

If deletion frees memory, then why do we need a destructor here?

+6
source share
9 answers

You need to call the destructor if there are other things you need to do other than just allocate memory allocation.

In addition to simple classes, there are usually.

Things like closing file descriptors or closing database connections, deleting other objects pointed to by member data in your object, etc.

A classic example is the implementation of the stack:

class myStack { private: int *stackData; int topOfStack; public: void myStack () { topOfStack = 0; stackData = new int[100]; } void ~myStack () { delete [] stackData; } // Other stuff here like pop(), push() and so on. } 

Now think about what happens if the destructor is not called every time one of your stacks is deleted. In this case, there is no automatic garbage collection in C ++, so the stackData memory will leak and you will end up.


This requirement of the destructor to remove all its resources moves down the tree in relation to the main types. For example, you might have a database connection pool with an array of database connections. The destructor for this will be delete for each individual database connection.

A single database connection can highlight many things, such as data buffers, caches, compiled SQL queries, etc. Thus, the database connection destructor would also need to delete about all of these things.

In other words, you have something like:

 +-------------------------------------+ | DB connection pool | | | | +-------------------------+---+---+ | | | Array of DB connections | | | | | +-------------------------+---+---+ | | | | | +-----------------------------|---|---+ | | +---------+ | +-> | DB Conn | +---------+ | +---------+ | DB Conn | <----+ / | \ +---------+ buffers | queries / | \ caches buffers | queries caches 

Releasing the memory of the database connection pool will not affect the existence of a separate database connection or other objects to which they point.

That's why I mentioned that only simple classes can leave without a destructor, and these are the classes that usually appear at the bottom of this tree above.

Class, for example:

 class intWrapper { private: int value; public: intWrapper () { value = 0; } ~intWrapper() {} void setValue (int newval) { value = newval; } int getValue (void) { return value; } } 

doesn't have a real need for a destructor, since freeing memory is all you need to do.


The bottom line is that new and delete are opposite ends of the same pole. The new call first allocates memory, and then calls the appropriate constructor code to get your object in a healthy state.

Then, when you are finished, delete calls the destructor to "tear down" your object, restores the allocated memory for this object.

+9
source

If deletion frees memory, then what is the need for a destructor here?

The point of the destructor is to execute any logic necessary to clear after your object, for example:

  • calling delete on other objects belonging to the destroyed object
  • Proper allocation of other resources, such as database connections file descriptors, etc.
+13
source

Suppose you have a class that dynamically allocates memory:

 class something { public: something() { p = new int; } ~something() { delete p; } int *p; }; 

Now dynamically select the something object:

 something *s = new something(); delete s; 

Now, if delete did not call the destructor, then s->p will never be freed. Therefore, delete should both call the destructor and free up memory.

+3
source

The destructor is responsible for freeing resources other than allocated memory. For example, if an object has a file descriptor, the destructor may invoke fclose on it.

+2
source

Cancels the memory occupied by this object. However, everything that was allocated by the object (and belongs to this object) must be taken care of in the destructor.

Also, in general ... Frequently asked questions ... are usually not mistaken.

+1
source

if you declare a normal class (not a pointer), it automatically calls the constructor and call destructor automatically when the program closes. If you declare as a pointer, it calls the constructor when initializing using the new one and does not automatically call the destructor until you delete this pointer with delete

0
source

The destructor must clear the changes that the constructor of the object and member functions could make for the state of the program. It can be anything - remove an object from a global list, close an open file, free allocated memory, close a database connection, etc.

0
source

A destructor would not be a required function . Languages ​​such as C, Java, C # do not have destructors. C ++ can also live without it.

Destructor is a special tool provided by C ++ (same as Constructor). It is called when the object is "destroyed . "

Destroy means that the area of ​​the object is officially completed, and any reference to this object will be illegal. For instance:

 A* foo () { static A obj; // 'A' is some class A *p = &obj; return p; } 

In the above code, obj is the static data created by type A ; foo() returns a reference to this obj , which is normal because obj.~A() is not yet called. Suppose obj non-stationary. The code will compile, however the A* returned by foo() now points to a memory location that is no longer an object of A Means β†’ operation is bad / illegal.

You should now be able to distinguish between memory deallocation and object destruction. Both are tightly connected, but there is a thin line.

Also remember that the destructor can be called in several places:

 int bar () { A obj; ... return 0; // obj.~A() called here ... return 1; // obj.~A() called here ... return 2; // obj.~A() called here } 

In the above example, obj.~A() will be called only once, but it can be called from any of the specified locations.

During destruction, you may want to do something useful. Suppose class A computes some result when an object is destroyed; it should print the result of the calculation. This can be done in C style (by putting some function in each return ). But ~A() is an easily accessible universal object.

0
source

In addition to the answers centered on objects allocated on the heap (with new ones that are freed up only with deletion) ... Don't forget that if you put an object on the stack (without using a new one), its destructor will be called automatically , and it will be removed from the stack (without calling delete) when it goes out of scope. Thus, you have one guaranteed function that will be executed when the object goes out of scope, and this is an ideal place to perform cleaning of all other resources allocated by the object (various handles, sockets ... and objects created on the heap by this object - if they should not survive this one). It is used in IIIII RAII .

0
source

Source: https://habr.com/ru/post/907545/


All Articles