From c++ FAQ: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9
Remember: delete p does two things: it calls the destructor and it deallocates the memory.
If delete deallocates the memory, then what's the need of the destructor here?
From c++ FAQ: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9
Remember: delete p does two things: it calls the destructor and it deallocates the memory.
If delete deallocates the memory, then what's the need of the destructor here?
You need to call the destructor in case there are other things that need to be done other than just de-allocating memory.
Other than very simple classes, there usually are.
Things like closing file handles or shutting down database connections, deleting other objects that are pointed to by members data within your object, and so forth.
A classic example is the implementation of a 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 of what would happen if the destructor was not called every time one of your stacks got deleted. There is no automatic garbage collection in C++ in this case so the stackData
memory would leak and you'd eventually run out.
This requiring of a destructor to delete all its resources moves down the tree towards the basic types. For example, you may have a database connection pool with an array of database connections. The destructor for that would delete
each individual database connection.
A single database connection may allocate a lot of stuff, such as data buffers, caches, compiled SQL queries and so on. So a destructor for the database connection would also have to delete
all those 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
Freeing the memory for the DB connection pool would not affect the existence of the individual DB connection or the other objects pointed to by them.
That's why I mentioned that only simple classes can get away without a destructor, and those are the classes that tend to show up at the bottom of that tree above.
A class like:
class intWrapper {
private:
int value;
public:
intWrapper () { value = 0; }
~intWrapper() {}
void setValue (int newval) { value = newval; }
int getValue (void) { return value; }
}
has no real need for a destructor since the memory deallocation is all you need to do.
The bottom line is that new
and delete
are opposite ends of the same pole. Calling new
first allocates the memory then calls the relevant constructor code to get your object in a workable state.
Then, when you're done, delete
calls the destructor to "tear down" your object the reclaims the memory allocated for that object.
so the stackData memory would leak and you'd eventually run out.
Didn't understand this. Delete deallocates the memory, so calling delete on a stack would deallocate it, so how are the memory leaks happening? –
Aciniform delete
) that it may need to do as part of that cleanup (like closing down legacy C libraries that don't use objects). –
Balneal has no real need for a destructor since the memory deallocation is all you need to do.
In that class, you didn't allocate any memory, so we don't we to deallocate anything. The destructor will still be needed for destroying the object intWrapper a;
? Right? –
Aciniform delete [] arr
will call the destructor once per object in the array ut may only deallocate one block of memory. –
Balneal You need to understand that memory allocation/deallocation and construction/destruction are two different things,
Well, I truly do NOT understand how they are different things. Ah! Do you mean the construction refers to the manual new
and allocation refers to the objects like classX objX;
? –
Aciniform new
does two things. The first is to allocate the memory (like C's malloc
) for your object, the second is to call your constructor so you can set the object up. At the other end delete
also does two things. It calls the destructor so you can tear down your object and then it reclaims the memory (a la C's free
). I'm not sure I can explain it any clearer and the comments are filling up so, if it's still not clear, you may want to consider asking a new question just on that aspect. –
Balneal If delete deallocates the memory, then what's the need of the destructor here?
The point of the destructor is to execute any logic required to clean up after your object, for example:
new
), and you want them to be deleted together with your object, you have to delete them in your destructor. See paxdiablos answer. –
Newspaperwoman You need to call the destructor in case there are other things that need to be done other than just de-allocating memory.
Other than very simple classes, there usually are.
Things like closing file handles or shutting down database connections, deleting other objects that are pointed to by members data within your object, and so forth.
A classic example is the implementation of a 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 of what would happen if the destructor was not called every time one of your stacks got deleted. There is no automatic garbage collection in C++ in this case so the stackData
memory would leak and you'd eventually run out.
This requiring of a destructor to delete all its resources moves down the tree towards the basic types. For example, you may have a database connection pool with an array of database connections. The destructor for that would delete
each individual database connection.
A single database connection may allocate a lot of stuff, such as data buffers, caches, compiled SQL queries and so on. So a destructor for the database connection would also have to delete
all those 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
Freeing the memory for the DB connection pool would not affect the existence of the individual DB connection or the other objects pointed to by them.
That's why I mentioned that only simple classes can get away without a destructor, and those are the classes that tend to show up at the bottom of that tree above.
A class like:
class intWrapper {
private:
int value;
public:
intWrapper () { value = 0; }
~intWrapper() {}
void setValue (int newval) { value = newval; }
int getValue (void) { return value; }
}
has no real need for a destructor since the memory deallocation is all you need to do.
The bottom line is that new
and delete
are opposite ends of the same pole. Calling new
first allocates the memory then calls the relevant constructor code to get your object in a workable state.
Then, when you're done, delete
calls the destructor to "tear down" your object the reclaims the memory allocated for that object.
so the stackData memory would leak and you'd eventually run out.
Didn't understand this. Delete deallocates the memory, so calling delete on a stack would deallocate it, so how are the memory leaks happening? –
Aciniform delete
) that it may need to do as part of that cleanup (like closing down legacy C libraries that don't use objects). –
Balneal has no real need for a destructor since the memory deallocation is all you need to do.
In that class, you didn't allocate any memory, so we don't we to deallocate anything. The destructor will still be needed for destroying the object intWrapper a;
? Right? –
Aciniform delete [] arr
will call the destructor once per object in the array ut may only deallocate one block of memory. –
Balneal You need to understand that memory allocation/deallocation and construction/destruction are two different things,
Well, I truly do NOT understand how they are different things. Ah! Do you mean the construction refers to the manual new
and allocation refers to the objects like classX objX;
? –
Aciniform new
does two things. The first is to allocate the memory (like C's malloc
) for your object, the second is to call your constructor so you can set the object up. At the other end delete
also does two things. It calls the destructor so you can tear down your object and then it reclaims the memory (a la C's free
). I'm not sure I can explain it any clearer and the comments are filling up so, if it's still not clear, you may want to consider asking a new question just on that aspect. –
Balneal Suppose you have a class that dynamically allocates memory:
class something {
public:
something() {
p = new int;
}
~something() {
delete p;
}
int *p;
};
Now let's dynamically allocate a something
object:
something *s = new something();
delete s;
Now, if the delete
didn't call the destructor, then s->p
would never be freed. So delete
has to both call the destructor and then deallocate the memory.
The destructor is in charge of freeing resources other than the object's allocated memory. For instance, if the object has a file handle open, the destructor could call fclose
on it.
It deallocates the memory taken up by that object. However, anything that has been allocated by the object (and owned by that object) needs to be taken care of in the destructor.
Also, in general ... FAQs ... usually not wrong.
if you declare a class normal (not pointer), it automatically calls constructor and call destructor automatically when the program closes. If you declare as pointer, it call the constructor when initializes using new and does not call destructor automatically until you call delete that pointer using delete
The destructor is there to clean up the changes that the object constructor and member functions might have done to the program state. That can be anything - remove the object from some global list, close an opened file, free allocated memory, close a database connection, etc.
The destructor would not have been a mandatory feature. The languages like, C, Java, C# don't have destructors. C++ also can live without it.
Destructor is a special facility provided by C++ (same as Constructor). It's called when an object is "destroyed".
Destroy means, the object scope is officially finished and any reference to that object will be illegal. For example:
A* foo ()
{
static A obj; // 'A' is some class
A *p = &obj;
return p;
}
In above code, obj
is a static
data created of type A
; foo()
returns a reference to that obj
which is ok, because obj.~A()
is not yet called. Suppose obj
is non-static. The code will compile, however, A*
returned by foo()
is now pointing to a memory location which is no more an A
object. Means -> the operation is bad/illegal.
Now, you should be able to distinguish between deallocation of the memory and the destruction of the object. Both are tightly coupled, but there is a thin line.
Also remember that destructor can be called at multiple places:
int bar ()
{
A obj;
...
return 0; // obj.~A() called here
...
return 1; // obj.~A() called here
...
return 2; // obj.~A() called here
}
In above example, obj.~A()
will be called only once, but it can be called from any of the places shown.
During the destruction, you may want to do some useful stuff. Suppose class A
calculates some result, when the object destroys; it should print the result of calculation. It can be done in C
style way (putting some function at every return
statement). But ~A()
is a readily available one-stop facility.
but it can be called from any of the places shown
How's that possible? When the return 0
is met, the funtion returns, and the remaining code can NEVER get executed, isn't it? –
Aciniform obj.~A()
is called only once, but compiler emits it code at all the above places shown. Because compiler doesn't know that at runtime which return
will be executed. –
Mariannemariano In addition to answers focused on the objects allocated on the heap (with new; which are deallocated only with delete)...Don't forget that if you place the object on the stack (so, without using new), its destructor will be called automatically and it will be removed from the stack (without calling delete) when it goes out of scope. So you have one function that is guaranteed to be executed when object goes out of the scope and that is perfect place to perform cleanup of all other resources allocated by the object (various handles, sockets...and objects created on the heap by this object - if they must not outlive this one). This is used in the RAII idiom.
© 2022 - 2024 — McMap. All rights reserved.
std::string
andstd::vector
and such), you don't need to write a destructor yourself. If it doesn't do the right thing (if your members arechar*
orFILE*
or whatever), you must write a destructor doing the right thing. (Note that destructing a pointer does nothing.) So if you want to executedelete member_pointer
before an object dies, you have to explicitly say so in the destructor. See this related FAQ for details. – Gambeson