Traditional C Memory Management

Traditional C++ Memory Management

You’ve already seen how to create and delete objects dynamically in C++ using the new and delete operators, but let’s review how the system works.

Creating Objects

Objects are created dynamically using the new operator, which does the following three things:

  • It allocates memory for the object.

  • It calls a constructor to initialize the object.

  • It returns a pointer to the object.

The following code fragment shows how to create an object belonging to the Account class:

// Create an object to represent Account number 1234567 Account* pa = new Account(1234567); 

Dynamically created objects have their memory allocated from the heap—the pool of free memory allocated to the process—whereas local variables have their memory allocated on the program’s stack. A dynamically created object actually consists of two parts: the object and the pointer you use to access it.

Deleting Objects

Local variables are created on the stack, and they’ll be destroyed when they go out of scope. In fact, local variables are also known as automatic variables, a name that reflects the fact that they’re automatically created and destroyed as necessary.

In contrast, unmanaged C++ requires you to manage the lifetime of dynamically created objects yourself. Consider the following code fragment:

void SomeFunction() { // Declare an integer to represent the account number long num = 123456; // Create an object to represent Account number 1234567 Account* pa = new Account(num); }

Two variables go out of scope at the closing brace and will be destroyed: the long num and the pointer pa. The actual Account object isn’t automatically destroyed but will exist until it’s destroyed or until the program finishes.

You destroy objects using the delete operator, as shown here:

// Create an object to represent Account number 1234567 Account* pa = new Account(num); // Use the Account // Destroy the Account delete pa;

The delete operator takes a pointer to the object and performs two operations:

  • It executes the class destructor so that you can tidy up the object state.

  • It gives the memory back to the operating system.

Advantages and Disadvantages of Manual Memory Allocation

There are advantages and disadvantages with manual memory allocation. The main—some people would say the only—advantage of manual memory allocation is that you have very precise control over when an object is destroyed, so you are not using memory for an instant longer than necessary.

A second advantage is the use of destructors: when you destroy an object, code is automatically executed to tidy up the object. This process ensures that objects are always properly tidied up without intervention by the programmer.

There are two disadvantages to calling delete manually to get rid of unwanted objects: calling it too late (or not at all), and calling it too early.

Neglecting to call delete isn’t usually fatal to your program, but it can have unwanted consequences. The most common of these is that your program will hang on to memory longer than it needs to, a condition known as memory leakage. In some cases, memory leakage can be fatal. Consider the following code fragment:

void lineDraw(int x1, int y1, int x2, int y2) { // Create a Pen to draw the line... Pen* p = new Pen(Black, OnePixelWide, Dashed); // Call some graphics library function to draw the line drawTheLine(p, x1,y1, x2,y2); // Forget to delete the Pen // delete p; }

Suppose that each Pen object is 10 bytes in size and that the lineDraw function is called 10,000 times. If the programmer forgets to delete the Pen object, this one routine will leak 100,000 bytes of memory. In prehistoric times—say, when Microsoft Windows was at version 3—computers didn’t have much memory, and a badly behaved program could consume all the free memory and crash the system.

Deleting an object too early—or at the wrong time—is a much more serious matter. If an object is deleted too early, someone might try to use it later. This usually results in the program failing. However, it’s sometimes difficult to decide just when an object should be released. Here’s an example:

// Create an object SomeObject* pObj = new SomeObject(); // Pass it to a function... aFunction(pObj); // Use the object pObj->doSomething(); // BANG! ... void aFunction(SomeObject* pp) { // Use pp pp->doThis(); // We’re done with the object - or are we? delete pp; }

The code creates an object and then passes the pointer to a function. The function uses the object through the pointer, thinks that the object is finished, and calls delete. When the function returns, the calling code tries to use the object with predictable results.

The problem is deciding who has the responsibility for deleting the object—in other words, who owns the object—and ownership can be surprisingly hard to determine in large or complex projects.

Microsoft Visual C++  .NET(c) Step by Step
Microsoft Visual C++ .NET(c) Step by Step
ISBN: 735615675
Year: 2003
Pages: 208 © 2008-2017.
If you may any questions please contact us: