Solved

[noob][c++] class::destructor  how do I write it?

Posted on 2007-11-16
46
338 Views
Last Modified: 2010-04-01
http://www.cplusplus.com/doc/tutorial/classes.html


// 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;
}












before I understand how to use a destructor, perhaps what I should ask first is, why use stack,
http://www.experts-exchange.com/Programming/Languages/CPP/Q_22965924.html
and then I'll ask

why use pointers for these

 int *width, *height;


0
Comment
Question by:Troudeloup
  • 14
  • 13
  • 12
  • +3
46 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 20299450
>>why use pointers for these

There is no other reason but the educational purpose. Usually, you'd allocate either large objects or data that is to persist over the duration of a function's scope on the heap. In the above, the heap allocation only serves demonstration purposes, but has no real background other than that.
0
 
LVL 20

Expert Comment

by:ikework
ID: 20299477
>> destructor  how do I write it?

you already did it:

CRectangle::~CRectangle () {
  delete width;
  delete height;
}

the "~" before the class-name indicates that is the destructor


ike
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20299758
>>>> why use pointers for these
>>>>  int *width, *height;

The only reason is that otherwise you wouldn't a destructor. IMO, it is a bad sample for a class with destructor, normally you would have somewhat like

class Buffer
{
      unsigned char* buf;
      int siz;
public:
      Buffer(int s) : buf(new unsigned char[s]), siz(s) {}
     ~Buffer() { delete []buf; }

};

Regards, Alex
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20299767
>>>> you wouldn't a destructor.
should be
      you wouldn't need a destructor.
0
 
LVL 40

Expert Comment

by:evilrix
ID: 20299879
Tip...

It is usually inadvisable to throw an exception from a destructor in C++, since the destructor may itself be called during the stack-unwinding caused by another exception. If the second exception is allowed to propagate beyond the destructor, the program is immediately terminated.

0
 

Author Comment

by:Troudeloup
ID: 20300416
just so I know which part to look at,
can you trim this down so that I can tell what's the minimum you have to have to put it on stack?
without pointers.


// 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;
}

0
 
LVL 86

Expert Comment

by:jkr
ID: 20300509
To halve all storage on the stack, use

lass CRectangle {
    int width, height;
  public:
    CRectangle (int,int);
    ~CRectangle ();
    int area () {return (width * height);}
;};

CRectangle::CRectangle (int a, int b) {

  width = a;
  height = b;
}

CRectangle::~CRectangle () {
 
  // nothing to do...
}

int main () {
  CRectangle rect (3,4), rectb (5,6);
  cout << "rect area: " << rect.area() << endl;
  cout << "rectb area: " << rectb.area() << endl;
  return 0;
}

Basically, that is turning the integers into non-pointers again.
0
 

Author Comment

by:Troudeloup
ID: 20300565
beautiful ^_^b

how about to put them on the heap,

so destructor is necessary?
0
 
LVL 86

Expert Comment

by:jkr
ID: 20300626
The whole thing on the heap would be pretty much like the original:

#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 = new CRectangle(3,4);
  CRectangle* rect = new CRectangle rectb (5,6);
  cout << "rect area: " << rect->area() << endl;
  cout << "rectb area: " << rectb->area() << endl;
  delete rect;
  delete rectb;
  return 0;
}
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20300629
>> how about to put them on the heap,
>>
>> so destructor is necessary?

Indeed ... The data allocated on the heap using new will have to be cleaned up by the destructor using the corresponding delete.
0
 

Author Comment

by:Troudeloup
ID: 20300691
ok back to square zero ..

in this context,

what does this do?

    int *width, *height;
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20300716
>> what does this do?
>>
>>     int *width, *height;

It declares two pointers to int named width and height.
0
 
LVL 86

Expert Comment

by:jkr
ID: 20300721
These two variables are declared as pointers to integers, and then assigned memory to store integers using

  width = new int;
  height = new int;

See also http://www.cplusplus.com/doc/tutorial/pointers.html
0
 

Author Comment

by:Troudeloup
ID: 20300756
I thought pointers are used when we don't want to pass by value and that was it,



so this

width = new int;
  height = new int;
  *width = a;
  *height = b;



really means that width and height is going to be declared as int type and put on heap,
and then

why not just

weight = a;
height = b; ?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20300778
>> really means that width and height is going to be declared as int type and put on heap,

You can put it like that, yes.


>> why not just
>>
>> weight = a;
>> height = b; ?

Because weight and height are the pointers to the values - they're not the values themselves. You need to dereference the pointers to get to the values they're pointing to :

  *width = a;
  *height = b;
0
 
LVL 86

Expert Comment

by:jkr
ID: 20300779
>>why not just
>>weight = a;
>>height = b; ?

Well, this exaple just served educational purposes to demonstrate the use of heap allocated memory. In "real life", people would use what you wrote above.
0
 

Author Comment

by:Troudeloup
ID: 20300818
Because weight and height are the pointers to the values - they're not the values themselves. You need to dereference the pointers to get to the values they're pointing to :

Well, this exaple just served educational purposes to demonstrae the use of heap allocated memory. In "real life", people would use what you wrote above.



i don't understand.
0
 
LVL 86

Expert Comment

by:jkr
ID: 20300843
This is an example to intruduce heap allocation to students. Nobody would allocate two simple integers on the heap in a real program.
0
 

Author Comment

by:Troudeloup
ID: 20300862
ok, but they are the way to allocate things on the heap in the real program,

then I need to ask


what's this?

  *width = a;
  *height = b;
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20300887
     int *height = new int;

declares height as a pointer to and int. It's actually the memory address of the int value. Concepyually it looks something like this :

                             -------
        height  ---->  |      |
                             -------

The block is the part of memory (on the heap) that is allocated using new, and that can contain 1 int.
height is the address of that memory block, and is thus pointing to that block.

All access to the int value happens using that address (pointer), but that means that each time you have to dereference the pointer (ie. "follow" the pointer) to get to the int value :

        *height = 5;

gives :

                             -------
        height  ---->  |  5  |
                             -------
0
 
LVL 86

Expert Comment

by:jkr
ID: 20300890
These two lines assigne the values of a and b to the memory that width and height point to

*ptr

refers to the memory a pinter points to - you will find more info at http://www.cplusplus.com/doc/tutorial/pointers.html
0
 

Author Comment

by:Troudeloup
ID: 20300960
i have to use pointer to put them onto heap?

if

  *width = a;
  *height = b;

also put the value of a into *width (themselves )

how is it differnt with

width = a;
height = b;

?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20300975
As I said : width and height contain the addresses, not the values, so this :

       width = a;
       height = b;

overwrites the addresses. You don't want that - you want to set the values that can be found at those addresses :

      *width = a;
      *height = b;
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 86

Expert Comment

by:jkr
ID: 20300997
Everything that goes on the heap needs a pointer in some way, see  http://en.wikipedia.org/wiki/Dynamic_memory_allocation
0
 

Author Comment

by:Troudeloup
ID: 20301002
the address of width and height becomes that of a and b


aw, this is awsome!
0
 
LVL 86

Expert Comment

by:jkr
ID: 20301026
>>the address of width and height becomes that of a and b

No, the memory that width and height point to becomes a and b
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20301030
>> the address of width and height becomes that of a and b

No. For that you'd have to do this :

       width = &a;
       height = &b;

But let's not confuse you more.

Again :

       width = a;
       height = b;

overwrites the POINTERS width and height with the VALUES a and b. As you see, that's not valid - they're incompatible. To do it correctly, you need to do :

      *width = a;
      *height = b;

which overwrites the VALUES pointed to by width and height with the VALUES a and b. This is ok - they're compatible.
0
 

Author Comment

by:Troudeloup
ID: 20301036
the value at the address pointed by them now contains the values a and b?
0
 
LVL 86

Expert Comment

by:jkr
ID: 20301047
Yes, that's it.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20301054
>> the value at the address pointed by them now contains the values a and b?

If you did :

      *width = a;
      *height = b;

then yes.
0
 

Author Comment

by:Troudeloup
ID: 20301055
ok so in short, i do this

width = new int;
  height = new int;
  *width = a;
  *height = b;


to put them on the heap
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20301060
Exactly.
0
 
LVL 86

Expert Comment

by:jkr
ID: 20301066
On point.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20301074
I think there's an echo here lol
0
 

Author Comment

by:Troudeloup
ID: 20301083
take a look at the beginning of this class

class CRectangle {
    int *width, *height;



this is odd -  I thought you have to create variables first before you can add point notations like  * and & to them.


I think this is related to the heap thing, what does this mean?
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20301096
>> I think this is related to the heap thing, what does this mean?

As we've already said a few times :

        int *width, *height;

declares two pointers to int named width and height. Read * as "pointer".
0
 
LVL 86

Expert Comment

by:jkr
ID: 20301104
Again take the time to read http://www.cplusplus.com/doc/tutorial/pointers.html - the notation is common, it only declares the pointers without having them point to a memory location. That is done by using

width = new int;
height = new int;
0
 

Author Comment

by:Troudeloup
ID: 20301113
what is that?

That is done by using
0
 
LVL 86

Expert Comment

by:jkr
ID: 20301130
'new' allocates the meory and the address returned by 'new' is assigned to height and width.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20303888
>>>> take a look at the beginning of this class
>>>> class CRectangle {
>>>>      int *width, *height;
>>>> this is odd -  I thought you have to create variables
>>>> first before you can add point notations like  * and &

You better would write the above sample as

class CRectangle
{
private:
        int*    pwidth;
        int*    pheight;
        ....

You then would see that the asterisk 'belongs' to the int what makes it a 'pointer to int' type. A 'int' type and a 'int*' type are completely different types, same as a 'char' and a 'char*' were completely different. While the first is a signed 8bit integer running from -128 to 127 is the second a pointer pointing to the first char of a char array (sequence of chars better known as 'string').

You can even make it more obvious that int* is a new type by using a 'typedef'.

typedef int* IntPtr;   // defines a new type 'pointer to inr' named 'IntPtr'

Then you can do

class CRectangle
{
private:
        IntPtr  pwidth;
        IntPtr  pheight;
        ....
public:
       CRectangle(int w, int h)
             :  pwidth(new int), pheight(new int)
       {
              *pwidth = w;
              *pheight = h;
       }


>>>>        :  pwidth(new int), pheight(new int)

That is called an initialiser list. It is good practice in C++ to initialise all member which are not class members (so that they don't have a built-in initializer by means of a constructor) int the initializer list.

In the sample, both member pointers get initialized with a new address from heap.

>>>>              *pwidth = w;

That fills the address with the value passed as argument to the constructor.

An alternative way to fill the storage is memcpy:

    memcpy(pwidth, &w, sizeof(int);

You could read it like 'copy memory of a size of an int - e. g. 4 bytes - from address of variable w to pointer address pwidth'. You wouldn't use memcpy to assign int variables cause

     *pwidth = w;

is much shorter. But to illustrate what the statement actually does the memcpy may help. And if the right side isn't an integer (value) but a 'buffer' - a sequence of bytes - somehow typed with a pointer type, then memcpy is the usual way to assign memory from one storage to another:

    unsigned char buf[128] = { 0 };
    char text[128] = "";
    int  len = 0;

    int nbytes = readBufferFromSomewhere(buf, sizeof(buf) );  // 128
   
    // assume the first 4 bytes read into the buffer is the
    // integer length of a string following the length
    // means the buffer looks like  [11]Hello World
    // where the [11] is a binary integer.

    if (nbytes > 4)
    {
            // read len from buffer using memcpy
            memcpy(&len, buf, sizeof(int));

            if (len > 0 && len < sizeof(text))
            {
                   memcpy(text, &buf[sizeof(int)], len);
                   text[len] = '\0';
            }
    }

>>>> memcpy(&len, buf, sizeof(int));

copy 4 bytes (sizeof(int) ) from pointer address 'buf' to address of variable 'len'.

Note, in C/C++ there is an equivalence of pointers and arrays. Actually, an array is a pointer pointing to the first element of the array.

>>>> memcpy(text, &buf[sizeof(int)], len);
copy 'len' bytes from address of buf[4] what is the address of the 5th unsigned char of the array 'buf' to char array 'text' - more precisely to the address of the first char element of array 'text'.

>>>>                   text[len] = '\0';

In C/C++ char arrays normally are terminated by a zero char. That way functions taking a char* as argument can determine the length of the 'string' array by searching for the first '\0' zero character.

Extra note:
 
>>>>    unsigned char buf[128] = { 0 };

That makes an array all zeros.

>>>>   char text[128] = "";

That only sets a zero char '\0' to the first char element, thus terminating it to 0 length. All other chars may have any arbitrary char value.

If I would have made

   char text[128] = { 0 };

then all chars were have have been zero in the text buffer.

Then I could omit the

          text[len] = '\0';

after memcpy as the initialization already provides it.

Regards, Alex
0
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 500 total points
ID: 20303941
>>>>         int*    pwidth;
You could/should use a 'p' prefix for pointer variables. That makes things easier especially if pointers were a new experience for you.

Some developers coming from C often do not use the 'p' prefix cause they are used to pointers and look at a pointer as only a different 'view' on a (non-pointer) type. They do not see much difference in passing  f(i) where i is a pointer or f(&i) where i is an int and indeed the compiler will tell them where to use the one or the other.  On the other hand in C++ there are only a few cases where you really *have* to use pointers (the above Rectangle members do not belong to these cases), you mostly can use 'references' or 'copies' instead, so a good pointer notation may help you do avoid using pointers where it is not needed.

IMO, there are only four ocassions in C++ where you should use pointers:

1. Baseclass pointers stored in a container for virtual use.
Here the pointers may point to objects of different derived classes. And the only way to store them is by use of baseclass pointers.

2. Function pointers
That is pointers to functions which can be used to assign different functionalities to some 'registered' information, e. g. to a 'window' within a GUO application.

3. Pointers for internal use in a helper class, container class or utility

See the 'buffer' example above.

4. Pointers used in an interface you have to supply.

If a library you were using such as a graphic library requires a pointer as an argument or return type, there is no other way than to using pointers. Nevertheless, you always could/should use such a pointer like a 'black box', like a 'handle' which is only used for the interface but not really interpreted as a pointer variable *or* where that is not possible turn it back to a non-pointer variable:

    Image image;   // create a image on the stack
    // call the function which requires a pointer to Image
    if (getImageFromSomewhere(&image))
    {
           int wid = image.getWidth();  // here we were using non-pointer again
           ...
    }

Regards, Alex




0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20389561
Were the other posts unhelpful ?
0
 

Author Comment

by:Troudeloup
ID: 20389565
i find his final anwser unclutered


i'll distribute points evenly in the future.
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 20390823
You don't have to distribute points evenly if the answers were not evenly helpful. The point is that you assign points to all answers that helped you, and the amount of points you assign to each depends on how helpful it was.

Points are assigned for two reasons :

1) to thank the experts that have been helping you

2) but mainly to clearly indicate which replies answered the question, so that future readers of this question can easily find the information they need (including you yourself)

You know which posts helped you, so you can choose the right ones, but you seem to not put a lot of effort in this important process. You either pick the last post, or you pick all of the posts. That's an easy way out, but is generally not the good one. Please, put some more effort in giving the right points to the right posts !
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20391007
Though I was the 'lucky one' in that thread and thus may be looked on as being less objective, I wanted to confirm that Troudeloupe indeed tried to evenly distribute points over threads rather than within one thread. I generally think that it is the right of the asker to judge in a subjective way, same as a voter in a democracy, and contrary, experts shouldn't blame him for that. If we think on the many who do abandon a thread and where the points were (mostly) equally distributed finally by a moderator, I welcome each 'decision' which was done by the asker himself, even if I am not the one who gets the points. Of course, there are general recommendations for points assignments  and of course each asker should be well aware that a misjudgement or ignorance of an expert's help may have the consequence of less help from the 'by-passed' expert in future. But that's part of the game either.

Regards, Alex
0
 

Author Comment

by:Troudeloup
ID: 20391058
i ll improve myself in the future. stay tunned.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now