Constructors are useful because they let you initialize the state of an object whenever one is created. This gives you a guarantee that an object is always in a "known" state. That way you don't get left with objects that haven't been set up yet.
Granted the above example isn't really very practical, but it's not easy to come up with a simple example of where a constructor is really useful. They're more important with complicated classes.
Here's an example of why ctors/dtors can be important. Let's say you have a class that mimics a variable size array... like a vector:
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 27 28 29 30 31
|
class IntArray
{
private:
int* data;
int size;
public:
void Resize(int newsize) // change the size of the array
{
int* buf = new int[newsize]; // create the new buffer
int numtocopy = std::min(size,newsize); // the number of elements to copy
std::copy(data,data+numtocopy,buf); // copy the old data to the new buffer
delete[] data; // delete the old buffer
data = buf; // make the new buffer our data buffer
}
int& operator [] (int index)
{
return data[index];
}
};
//================
// now that we have this class, let's try to use it.
int main()
{
// let's make an array with 10 elements:
IntArray array;
array.resize(10); // EXPLODE - see below
}
|
The resize call would explode here because 'IntArray::data' has never been initialized, so it's a bad pointer. Trying to delete a bad pointer could corrupt memory, or just make the program crash.
We
could fix that with some kind of "initialize" funciton. Like this:
1 2 3
|
IntArray array;
array.initialize(); // initialize all our stuff
array.resize(10); // so that this is no problem
|
But that makes the class a pain to use. What if you forget to do that one time?
The better alternative is to make a constructor. Since they are guaranteed to be called whenever the object is created, you can make sure it's always initialized:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
class IntArray
{
//...
public:
IntArray()
{
data = 0;
size = 0;
}
};
int main()
{
IntArray array; // now this is initialized
array.resize(10); // so this is no problem!
}
|
The next problem here... is what happens when our array dies? We never delete the memory buffer. This will cause the program to leak memory. Therefore, writing a destructor is important to make sure the memory get properly cleaned up:
1 2 3 4 5 6 7 8 9
|
class IntArray
{
//...
public:
~IntArray() // when the object dies...
{
delete[] data; // clean up our allocated memory
}
};
|
That's why ctors and dtors can be useful.
Note the above class isn't practical. There are other issues regarding copying the array, but I'll save that for another day.