|
Glen McCluskey is a consultant with 15 years of experience and has focused on programming languages since 1988. He specializes in Java and C++ performance, testing, and technical documentation areas.
In this column we'll look at C++ replacements for malloc() and free(), the operators new() and delete(). To give an example of how these are similar and how they differ from their C counterparts, suppose that we want to allocate a 100-long vector of integers for some purpose. In C, we would say:
int* ip; With new/delete in C++, we would have:
int* ip; The most obvious difference is that the C++ approach takes care of the low-level details necessary to determine how many bytes to allocate. With the C++ new operator, you simply describe the type of the desired storage, in this example int[100]. The C and C++ approaches have several similarities:
malloc() returns NULL if the space cannot be obtained. Many versions of new in existing C++ compilers do likewise. However, the draft ANSI C++ standard says that a failure to obtain storage should result in an exception being thrown or should result in the currently installed new handler being invoked. I assume that NULL is returned. new Handlers The idea of a new handler can be illustrated as follows:
extern "C" int printf(const char*, A new handler is a way of establishing a hook from the C++ standard library to a user program. set_new_handler() is a library function that records a pointer to another function that is to be called in the event of a new failure. Deleting Arrays Note that saying: delete ip; instead of: delete [] ip; will work with some compilers in the example above. This is an area of C++ that has changed several times in recent years. There are a number of issues to note. The first is that new and delete in C++ have more than one function. The new operator allocates storage, just like malloc() in C, but it is also responsible for calling the constructor for any class object that is being allocated. For example, if we have a String class, saying: String* p = new String("xxx"); will allocate space for a String object and then call the constructor to initialize the String object to the value "xxx." In a similar way, the delete operator arranges for the destructor to be called for an object, and then the space is deallocated in a manner similar to the C function free(). If we have an array of class objects, as in: String* p = new String[100]; then a constructor must be called for each array slot, because each is a class object. Typically, this processing is handled by a C++ internal library function that iterates over the array. In a similar way, deallocation of an array of class objects can be done by saying: delete [] p; It used to be that you had to say: delete [100] p; but this feature is obsolete. The size of the array is recovered by the library function that implements the delete operator for arrays. The pointer/size pair can be stored in an auxiliary data structure, or the size can be stored in the allocated block before the first actual byte of data. What makes this a bit tricky is that all this work of calling constructors and destructors doesn't matter for fundamental data types like int:
int* ip;
This code will work in many cases because there are no destructors to call, and deleting a block of storage works pretty much the same whether it's treated as an array of ints or a single large chunk of bytes. But more recently, the ANSI Standardization Committee decided to break out the new and delete operators for arrays as separate functions so that a program can control the allocation of arrays separately from other types. For example, you can say:
void* operator new(unsigned int) {/* ... */ return
0;}
and the appropriate functions will be called in each case. This is kind of like defining your own versions of the malloc() and free() library functions in C. Defining Your Own new/delete Functions It is possible to define your own new and delete functions. For example:
void* operator new(size_t s)
size_t is a typedef, typically defined to mean "unsigned int." It's found in a header file that may vary between compiler implementations.
|
|
First posted: 4th February 1998 efc Last changed: 423 February 1998 efc |
|