Online Book Reader

Home Category

Professional C__ - Marc Gregoire [89]

By Root 1101 0
Memory with Destructors

Whenever you are finished with dynamically allocated memory, you should free it. If you dynamically allocate memory in an object, the place to free that memory is in the destructor. The compiler guarantees that the destructor will be called when the object is destroyed. Here is the Spreadsheet class definition from earlier with a destructor:

class Spreadsheet

{

public:

Spreadsheet(int inWidth, int inHeight);

~Spreadsheet();

// Code omitted for brevity

};

Code snippet from Spreadsheet\Spreadsheet.h

The destructor has the same name as the name of the class (and of the constructors), preceded by a tilde (~). The destructor takes no arguments, and there can only be one of them.

Here is the implementation of the Spreadsheet class destructor:

Spreadsheet::~Spreadsheet()

{

for (int i = 0; i < mWidth; i++) {

delete [] mCells[i];

}

delete [] mCells;

mCells = nullptr;

}

Code snippet from Spreadsheet\Spreadsheet.cpp

This destructor frees the memory that was allocated in the constructor. However, no rule requires you to free memory in the destructor. You can write whatever code you want in the destructor, but it is a good idea to use it only for freeing memory or disposing of other resources.

Handling Copying and Assignment

Recall from Chapter 6 that, if you don’t write a copy constructor and an assignment operator yourself, C++ writes them for you. These compiler-generated methods recursively call the copy constructor or assignment operator on object data members. However, for primitives, such as int, double, and pointers, they provide shallow or bitwise copying or assignment: They just copy or assign the data members from the source object directly to the destination object. That presents problems when you dynamically allocate memory in your object. For example, the following code copies the spreadsheet s1 to initialize s when s1 is passed to the printSpreadsheet() function.

#include "Spreadsheet.h"

void printSpreadsheet(Spreadsheet s)

{

// Code omitted for brevity.

}

int main()

{

Spreadsheet s1(4, 3);

printSpreadsheet(s1);

return 0;

}

Code snippet from Spreadsheet\SpreadsheetTest.cpp

The Spreadsheet contains one pointer variable: mCells. A shallow copy of a spreadsheet gives the destination object a copy of the mCells pointer, but not a copy of the underlying data. Thus, you end up with a situation where both s and s1 have a pointer to the same data, as shown in Figure 7-2.

If s were to change something to which mCells points, that change would show up in s1 too. Even worse, when the printSpreadsheet() function exits, s’s destructor is called, which frees the memory pointed to by mCells. That leaves the situation shown in Figure 7-3.

FIGURE 7-2

FIGURE 7-3

Now s1 has a pointer which no longer points to valid memory. This is called a dangling pointer.

Unbelievably, the problem is even worse with assignment. Suppose that you had the following code:

Spreadsheet s1(2, 2), s2(4, 3);

s1 = s2;

Code snippet from Spreadsheet\SpreadsheetTest.cpp

After both objects are constructed, you would have the memory layout shown in Figure 7-4.

FIGURE 7-4

After the assignment statement, you would have the layout shown in Figure 7-5.

FIGURE 7-5

Now, not only do the mCells pointers in s1 and s2 point to the same memory, but also you have orphaned the memory to which mCells in s1 previously pointed. That is why in assignment operators you must first free the memory referenced by the left-hand side, and then do a deep copy.

As you can see, relying on C++’s default copy constructor or assignment operator is not always a good idea.

Whenever you have dynamically allocated memory in a class, you should write your own copy constructor and assignment operator to provide a deep copy of the memory.

The Spreadsheet Copy Constructor

Here is a declaration for a copy constructor in the Spreadsheet class:

class Spreadsheet

{

public:

Spreadsheet(int inWidth, int inHeight);

Spreadsheet(const Spreadsheet& src);

// Code omitted for brevity

};

Code snippet from Spreadsheet\Spreadsheet.h

Return Main Page Previous Page Next Page

®Online Book Reader