Free Hosting

Destructors


destructor is another special kind of class member function that is executed when an object of that class is destroyed. They are the counterpart to constructors. When a variable goes out of scope, or a dynamically allocated variable is explicitly deleted using the delete keyword, the class destructor is called (if it exists) to help clean up the class before it is removed from memory. For simple classes, a destructor is not needed because C++ will automatically clean up the memory for you. However, if you have dynamically allocated memory, or if you need to do some kind of maintenance before the class is destroyed (eg. closing a file), the destructor is the perfect place to do so.
Like constructors, destructors have specific naming rules:
1) The destructor must have the same name as the class, preceded by a tilde (~).
2) The destructor can not take arguments.
3) The destructor has no return type.
Note that rule 2 implies that only one destructor may exist per class, as there is no way to overload destructors since they can not be differentiated from each other based on arguments.
Let’s take a look at a simple string class that uses a destructor:
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
32
33
34
35
class MyString
{
private:
    char *m_pchString;
    int m_nLength;
 
public:
    MyString(const char *pchString="")
    {
        // Find the length of the string
        // Plus one character for a terminator
        m_nLength = strlen(pchString) + 1;
 
        // Allocate a buffer equal to this length
        m_pchString = new char[m_nLength];
 
        // Copy the parameter into our internal buffer
        strncpy(m_pchString, pchString, m_nLength);
 
        // Make sure the string is terminated
        m_pchString[m_nLength-1] = '\0';
    }
 
    ~MyString() // destructor
    {
        // We need to deallocate our buffer
        delete[] m_pchString;
 
        // Set m_pchString to null just in case
        m_pchString = 0;
    }
 
    char* GetString() { return m_pchString; }
    int GetLength() { return m_nLength; }
};
Let’s take a look at how this class is used:
1
2
3
4
5
6
int main()
{
    MyString cMyName("Alex");
    std::cout << "My name is: " << cMyName.GetString() << std::endl;
    return 0;
} // cMyName destructor called here!
This program produces the result:
My name is: Alex
On the first line, we instantiate a new MyString class and pass in the C-style string “Alex”. This calls the constructor, which dynamically allocates memory to hold the string being passed in. We must use dynamic allocation here because we do not know in advance how long of a string the user is going to pass in.
At the end of main(), cMyName goes out of scope. This causes the ~MyString() destructor to be called, which deletes the buffer that we allocated in the constructor!
Constructor and destructor timing
As mentioned previously, the constructor is called when an object is created, and the destructor is called when an object is destroyed. In the following example, we use cout statements inside the constructor and destructor to show this:
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
32
33
class Simple
{
private:
    int m_nID;
 
public:
    Simple(int nID)
    {
        std::cout << "Constructing Simple " << nID<< std::endl;
        m_nID = nID;
    }
 
    ~Simple()
    {
        std::cout << "Destructing Simple" << m_nID << std::endl;
    }
 
    int GetID() { return m_nID; }
};
 
int main()
{
    // Allocate a Simple on the stack
    Simple cSimple(1);
    std::cout << cSimple.GetID() << std::endl;
 
    // Allocate a Simple dynamically
    Simple *pSimple = new Simple(2);
    std::cout << pSimple->GetID() << std::endl;
    delete pSimple;
 
    return 0;
} // cSimple goes out of scope here
This program produces the following result:
Constructing Simple 1
1
Constructing Simple 2
2
Destructing Simple 2
Destructing Simple 1
Note that “Simple 1″ is destroyed after “Simple 2″ because we deleted pSimple before the end of the function, whereas cSimple was not destroyed until the end of main().
As you can see, when constructors and destructors are used together, your classes can initialize and clean up after themselves without the programmer having to do any special work! This reduces the probability of making an error, and makes classes easy to use.

0 comments:

Blogger Template by Clairvo