Allocating and deallocating arrays, in detail

September 14, 2009

Dan_Saks-September 14, 2009

Last year and early this year, I wrote a couple of articles on dynamic allocation in C and C++ emphasizing the distinction between allocating objects and allocating raw (uninitialized) storage.1,2 When a program allocates an object, it not only allocates storage for the object, but also initializes that storage with a value appropriate for the type of object that will occupy that storage. When a program just allocates storage, it leaves that storage uninitialized.

I followed those articles with one that explained the distinction between deallocating objects and deallocating storage.3 When a program deallocates an object, it releases not only the storage occupied by the object, but also any other resources the object was using.

In each of those articles, I sketched out how C++ compilers translate new-expressions into more primitive operations. I also showed how to write C code that emulates the behavior of new-expressions. However, I stalled out when I got to array delete-expressions. I also left some details out of the code for both the C++ implementation and the C emulation of array new-expressions. This month, I'll fill in most of the missing pieces.

A recap
New-expressions in C++ allocate objects. Each new-expression is conceptually, if not actually, a two-step process: (1) allocate storage for an object, and (2) initialize it. For objects of class types, initializing an object usually involves calling a constructor.

For example, suppose class widget is defined as:

class widget
    {
public:
    widget();       // a constructor
    ~widget();      // a destructor
    // ...
    };

Then a new-expression such as:

pw = new widget ();

translates more-or-less into something like:

pw = static_cast<widget *>(operator new(sizeof(widget)));
pw->widget();

The first statement acquires storage for a widget object by calling operator new, and converts the address of that storage from type void * to type widget *. The second statement initializes the storage by applying widget's default constructor. (That second statement--an explicit constructor call--is not something you can actually write in C++.)

Delete-expressions in C++ deallocate objects. Each delete-expression is also a two-step process: (1) release resources that the object was using, and (2) deallocate the storage for the object. For objects of class types, releasing resources involves calling a destructor.

If pw is a pointer to an object of class type widget, a delete-expression such as delete pw; translates more-or-less into something like:

if (pw != NULL)
    {
    pw->~widget();
    operator delete(pw);
    }

< Previous
Page 1 of 5
Next >

Loading comments...