Dynamic Creation of Objects

Pointers can be used to manage storage that is allocated manually while the program is executing. The new and delete keywords allow this manual allocation and de-allocation of memory in the C++ language. This facility is very powerful. For example, we can create the memory space to manipulate an image or to open a temporary record at any point in the code. This feature can, however, lead to serious difficulties.

For an example of problems that can arise, see this code segment:

 int main()
 {
   Account *a = new Account("John", 10.50, 123456);  
   Account *b = new Account("Derek", 12.07, 123457);

   a->display();
   b->display();

   b = a;

   a->display();
   b->display();
 }

The full source code for this example is here - AccountDynamicCreation.cpp.

When run, this application gives the output as in Figure 3.12, “The Account Dynamic Allocation Example.”. The code dynamically creates two Account objects and assigns them to the a and b Account pointers. The display() method is called on both objects resulting in the display of two account details, John and Derek's accounts. The assignment b = a; is the key problem here. The only reference we have to these two "anonymous" objects is the two pointers. If one pointer is assigned to the other then any reference we had to the second object (Derek's account) is lost. This results in the object being lost in memory, and not capable of being de-allocated. This loss is called a memory leak. Since both pointers are now pointing at the same Account object, the same details will be displayed when the display() method is called on each pointer.

Figure 3.12. The Account Dynamic Allocation Example.

The Account Dynamic Allocation Example.

This can be further illustrated as in Figure 3.13, “The Account Dynamic Allocation Illustration.”.

Figure 3.13. The Account Dynamic Allocation Illustration.

The Account Dynamic Allocation Illustration.

After the assignment b=a the pointer b is pointing to the first Account object. The second object "Derek's" Account has no reference or pointer and so is lost. The memory associated with this object will only be deallocated (by the operating system) after the application has run to completion.

A further problem with the dynamic allocation/deallocation of data is that the delete call must be invoked by the programmer before the destructor of the class is called. For example, when a destructor is added to the code segment above that simply displays that an account is being destroyed (it could be doing something important like creating a paper record), we could use the code:

 int main()
 {
   Account *a = new Account("John",10.50, 123456);  
   Account *b = new Account("Derek",12.07, 123457);

   a->display();
   b->display();

   b = a;

   delete a;  // deletes John's account
 }

(The full source code for this example is here - AccountDynamicCreationTest.cpp).

Execution of the application will result in the output, as shown in Figure 3.14, “The Account Dynamic De-Allocation First Test.”:

Figure 3.14. The Account Dynamic De-Allocation First Test.

The Account Dynamic De-Allocation First Test.

So the destructor is called on the Account object with John's details, but the destructor is never called on the Account object with Derek's details.

Suppose the code is altered to call a delete on both pointers a and b, like:

 int main()
 {
   Account *a = new Account("John",10.50, 123456);  
   Account *b = new Account("Derek",12.07, 123457);

   a->display();
   b->display();

   b = a;

   delete a;  // deletes John's account
   delete b;  // tries to delete John's account again
 }

(The full source code for this example is here - AccountDynamicCreationTest2.cpp - Caution, this code when run may crash your computer.)

What would the output be? Well it would be as in Figure 3.15, “The Account Dynamic De-Allocation Second Test.”:

Figure 3.15. The Account Dynamic De-Allocation Second Test.

The Account Dynamic De-Allocation Second Test.

If you run this application on Microsoft Windows, Microsoft will apologise of the inconvenience for the error! You can tell them about the problem, but they probably don't really care!

So what is the problem? Well since both pointers a and b point at the same Account object, the first delete call deletes the object referenced by the pointer (John's account), but the second call to delete tries to delete something that is not there (John's account again), thus causing the crash.

When applying delete to a pointer to an object, it calls the destructor for the object before releasing its storage.