use of destructors

Hi all,

I am not sure if I get this example in the right way:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// example on constructors and destructors
#include <iostream>
using namespace std;
class CRectangle {
int *width, *height;
public:
CRectangle (int,int);
~CRectangle ();
int area () {return (*width * *height);}
};
CRectangle::CRectangle (int a, int b) {
width = new int;
height = new int;
*width = a;
*height = b;
}
CRectangle::~CRectangle () {
delete width;
delete height;
}
int main () {
CRectangle rect (3,4), rectb (5,6);
cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl;
return 0;
}


According to the text a destrucor is called when an object is destroyed. So, first we call CRectangle with rect(3,4) but the ~CRectangle () function will not be called because the object is still valid. After the second call with rectb(5,6) the old values will be erased by ~CRectangle because they are destroyed by the new values? So, in effect only rect(3,4) will be erased? A further question would be why one uses pointers in this example? Is it necessary? It seems overly convoluted to me.
Thanks in advance for some answers to my ongoing stupid questions.
Last edited on
"A destructor is another type of special member function. "

It is called implicitly when an object is destroyed. If you want to understand more about this, put a print function in there, run the program and see when its called.

in other words, when an object needs to be deleted , losing scope, etc the destructor will be called.

For good practice when you allocate dynamic memory in your program it is good practice to delete (destroy) any unused memory

For instance, if you are doing dynamic array allocation, it is good practice to put your delete code to destroy the allocated memory after its destructor is called.

~CRectangle should contain
delete [] somearray;
Last edited on
The delete process is defined here:
1
2
3
4
CRectangle::~CRectangle () {
delete width;
delete height;
}
Last edited on
A further question would be why one uses pointers in this example? Is it necessary? It seems overly convoluted to me.
You are right, there is no good reason to use them there.
Moreover they are dangerous, considerer
1
2
3
CRectangle a, b;
a = b;
CRectangle c(a);
As the pointers are copied (not their content), that will cause memory leaks and several deletions of the same pointer.
According to the text a destrucor is called when an object is destroyed. So, first the we call CRectangle with rect(3,4) but the ~CRectangle () function will not be called because the object is still valid. After the second call with rectb(5,6) the old values will be erased by ~CRectangle because they are destroyed by the new values? So, in effect only rect(3,4) will be erased?


No, the second call will not erase the old values. They're not old values at all. There are two instances of the class here, each with their own destructor. They will run independently when the object is destroyed.

1
2
3
4
5
6
7
int main()
{
   CRect recta, rectb;
   // Do stuff

   // Destructors for both CRect objects called here
}


Alternatively, if you had dynamically allocated CRects:
1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
   CRect* recta = new CRect;
   CRect* rectb = new CRect;

   // Do stuff

   delete recta;    // recta's destructor runs here
   
   // Do stuff

   delete rectb;    // rectb's destructor runs here
}
To be fair all the examples before were without pointers.
They started to use them with the introduction of the destructors.
Probably because there is generally not much to do in a Constructor if you don't have heap-allocated variables in your class.

It's generally a good idea to have each class take care of its own memory. It's also generally a good idea to check, and double check, that every "new'd" variable is deleted, and only those are deleted. If there is a chance that a CRect object is created without allocating memory, make sure not to call the delete on this!

E.g.:
1
2
3
4
5
6
7
8
9
class CRectangle {
    CRectangle (int,int);
    CRectangle (void) { } // 'Empty constructor'
}
int main() {
    CRectangle myRect;
    return 0;
    // Here, an error will be thrown, because myRect's deconstructor will (try to) delete uninitialized memory.
}

Sometimes, the empty constructor is required (e.g.: if you want to make an array of CRectangles). In those cases, make sure the deconstructor checks. (e.g.: if (width != nullptr) delete width; )
No, the second call will not erase the old values. They're not old values at all. There are two instances of the class here, each with their own destructor. They will run independently when the object is destroyed.

My problem is that ~CRectangle comes before the calculation of the area:
1
2
3
CRectangle (int,int);
~CRectangle ();
int area () {return (*width * *height);

So actually before the "Do Stuff" part...
Those are the function declarations. It doesn't matter that the appear sequentially in your class definition - they're not called in that order.

The code within ~CRectangle() doesn't actually execute until the object is destroyed.
Those are the function declarations. It doesn't matter that the appear sequentially in your class definition - they're not called in that order.


Oh, OK, I see that now!
Topic archived. No new replies allowed.