2.9 Dynamic Objects


Dynamic objects have lifetimes unbounded by the existence of the scope in which they were created. Thus, objects can be constructed in a function that continue to exist after the function returns; or objects can be created in an if-then construct that exists after the if-then construct has been executed. Dynamic objects give the programmer greater flexibility in managing objects. However, the programmer also assumes greater responsibility for insuring that dynamic objects are managed properly. Two problems that can occur with dynamic objects are destructing the object too soon and failing to destruct the objects at all.

A dynamic object is created using a "new" operator that returns a pointer to the newly constructed object and is destructed by a "delete" operator. A pointer variable is used to hold the pointer to the object that is returned by the new operator. The delete operator takes a pointer variable as an operand and destructs the object pointed to by that variable. The following example illustrates how dynamic objects can be created and deleted.

  Frame *window, *view;                // declaration of pointer variables

   window = new Frame("First", 10, 20, 50, 50); // create a new Frame object
   view   = new Frame("Second",70, 20, 50, 50); // create a new Frame object

   Frame *edit = new Frame ("Editor", 50, 75, 100, 100); // combine declaration of pointer
                                                         // variable and object construction

   Frame *default = new Frame;          // use default constructor values

   delete window;                       // destruct window Frame
   delete view;                         // destruct view   Frame
   delete edit;                         // destruct edit   Frame
   delete default;                      // destruct default Frame

In this example, window and view are declared as variables that point to Frame objects. It is important to realize that this declaration does not create two frames; it merely creates two variables that will point to Frame objects that are created sometime in the future. The two Frame objects are then created and the variables "window" and "view" are set pointing to these objects. The declaration of the pointer variable and the construction of the object to which it points can be combined in a single statement as shown with the edit and default. Finally, the four Frame objects are deleted.

Notice the syntax of creating dynamic objects. The name of the class appears immediately after the keyword "new." The constructor arguments, if any, are given in parentheses after the name of the class. When there are no constructor arguments, the parenthesis are omitted as shown in the creation of the default object.

An operation is applied to a dynamic object using the -> operator. This "arrow" operator is two adjacent characters, a minus sign and a greater than symbol. An exaple of operating on a dynamic object is the following:

 Frame* display = new Frame ("A Display", 10, 20, 100, 200);

  display->MoveTo(50, 50);
  display->Resize(200, 200);

In this example the display object is moved and resized using the arrow operator to apply the corresponding methods.

Two types of serious errors can occur if dynamic objects are not used properly. These errors are serious in two senses. First, the errors can cause the program to abort or exhibit unpredictable behavior. Second, in real programs, the causes of these errors are among the hardest to find.

The first type of error that can occur with dynamic objects is deleting a dynamic object too soon. The example below shows a situation where a Frame object is pointed to by two different variables, display and view. The shared object is destructed by the "delete display;" statement. The error then occurs when, using the view variable, an attempt is made to operate on the now destructed object.

  Frame *display = new Frame ("Shared", 10, 20, 100, 100);
   Frame *view;

   view = display;              // both point to same Frame object

   display->MoveTo(50, 50);     // OK - moves shared Frame object
   view->Resize(200, 200);      // OK - resizes shared Frame object

   delete display;              // delete shared object

   view->MoveTo(20, 20);        // ERROR - object already deleted!

The best outcome of using already-deleted objects is that the program aborts. In this case, the debugging can usually begin at or very close to the actual point of the error. However, and much worse, the program may continue to execute. The run-time system may not be able to detect that the object is deleted and will proceed to alter the memory previously occupied by the object. The effects of this are unpredictable. Often, some other part of the program will discover that an object has mysteriously been damaged. Finding the source of this problem in a large program is extremely difficult.

The second type of error that can occur with dynamic objects is not deleting a dynamic object that is no longer accessible. This type of error is referred to as a "memory leak" because the pool of available memory appears to be leaking away. In a long-running program (air-traffic control, electronic funds transfer, etc.), sufficient memory can be leaked away so that the program aborts. Severe memory leaks can cause hundreds of megabytes of memory to be leaked.

An example of a memory leak is shown in the example below.

  Frame *display;
   
   for (int i=0; i<100; i++) {
        display = new Frame ("Memory Leak", 50, 50, 100, 100);
        // display used but not deleted
   }

In this example, 100 Frame objects are created but none of them are deleted though all but the last of these Frame objects are inaccessible because the pointer to them has been overwritten. However, the memory to hold these objects is still allocated. To the run-time system, the program is still using the memory, but the program has lost any means of finding the objects. Thus, the memory is allocated but inaccessible - it has leaked away.

The errors in the two examples immediately above are easly identified because so little code is involved in each example. But imagine a program with tens of classes, hundreds of methods, and thousands of objects, where numerous objects are shared between various parts of the system. In these cases - the really important ones - it is extremely difficult to locate what causes these types of errors.

 

Tasks

  1. Simple Dialog: Write a program that displays a Frame containing the text "Click Here for Help" . When the user clicks the left mouse button in this Frame, a new Frame is dynamically created that contains two lines of text: "Yes Master. You Rang?" and "Click to Dismiss." . When the user clicks the left mouse button in the dynamically created Frame, the Frame should be deleted. Analyze your program to determine if there is the potential for a memory leak. You do not have to fix this problem; simply identify it.
  2. Rewrite the Corner Tour program using only one dynamic Frame object.
  3. Rewrite the Corner Tour program so that a new dynamic Frame object is created at each corner and the object in the previous corner is deleted.
  4. Rewrite the Border Walk program using only one dynamic Frame object.
  5. Rewrite the Border Walk program so that a new dynamic Frame object is created at each step.
  6. Write a program that deliberately accesses a deleted Frame object. How did the program behave?
  7. Write a program that leaks Frame objects. How long did the program run before aborting? How did it abort?
  8. What is the main difference between the declarations "Frame display;" and "Frame *display;" ?
  9. What is the main difference between the declarations "Frame display[10];" and "Frame *display[10];"?



©1998 Prentice-Hall, Inc.
A Simon & Schuster Company
Upper Saddle River, New Jersey 07458

Legal Statement

 

 

 

ÿ