C++ Migration Guide

New Forms of new and delete

There are four issues regarding the new forms of new and delete:

The old rules are used by default in compatibility mode, and the new rules are used by default in standard mode. Changing from the default is not recommended, because the old run-time library (libC.so) depends on the old definitions and behavior, and the new standard library (libCstd.so) depends on the new definitions and behavior.

The compiler predefines the macro _ARRAYNEW to the value 1 when the new rules are in force. The macro is not defined when the old rules are in use. The following example is explained in more detail in the next section:


// Replacement functions
#ifdef _ARRAYNEW
    void* operator new(size_t) throw(std::bad_alloc);
    void* operator new[](size_t) throw(std::bad_alloc);
#else
    void* operator new(size_t);
#endif

Array Forms of new and delete

The C++ standard adds new forms of operator new and operator delete that are called when allocating or deallocating an array. Previously, there was only one form of these operator functions. In addition, when you allocate an array, only the global form of operator new and operator delete would be used, never a class-specific form. The C++ 4.2 compiler did not support the new forms, since their use requires an ABI change.

In addition to these functions:

void* operator new(size_t);

void operator delete(void*);

there are now:

void* operator new[](size_t);

void operator delete[](void*);

In all cases (previous and current), you can write replacements for the versions found in the run-time library. The two forms are provided so that you can use a different memory pool for arrays than for single objects, and so that a class can provide its own version of operator new for arrays.

Under both sets of rules, when you write new T, where T is some type, function operator new(size_t) gets called. However, when you write new T[n] under the new rules, function operator new[](size_t) is called.

Similarly, under both sets of rules, when you write delete p, operator delete(void*) is called. Under the new rules, when you write delete [] p, operator delete[](void*) is called.

You can write class-specific versions of the array forms of these functions, as well.

Exception Specifications

Under the old rules, all forms of operator new returned a null pointer if the allocation failed. Under the new rules, the ordinary forms of operator new throw an exception if allocation fails, and do not return any value. Special forms of operator new that return zero instead of throwing an exception are available. All versions of operator new and operator delete have an exception-specification. The declarations found in standard header <new> are:


namespace std {
      class bad_alloc;
      struct nothrow_t {};
      extern const nothrow_t nothrow;
}
// single-object forms
void* operator new(size_t size) throw(std::bad_alloc);
void* operator new(size_t size, const std::nothrow_t&) throw();
void operator delete(void* ptr) throw();
void operator delete(void* ptr, const std::nothrow_t&) throw();
// array forms
void* operator new[](size_t size) throw(std::bad_alloc);
void* operator new[](size_t size, const std::nothrow_t&) throw();
void operator delete[](void* ptr) throw();
void operator delete[](void* ptr, const std::nothrow_t&) throw();

Defensive code such as the following example no longer works as previously intended. If the allocation fails, the operator new that is called automatically from the new-expression throws an exception, and the test for zero never occurs.


T* p = new T;
if( p == 0 ) {           // No longer OK
    ...                  // Handle allocation failure
}
...                      // Use p

There are two solutions:

If you prefer not to use any exceptions in your code, you can use the second form. If you are using exceptions in your code, consider using the first form.

If you did not previously verify whether operator new succeeded, you can leave your existing code unchanged. It then aborts immediately on allocation failure instead of progressing to some point where an invalid memory reference occurs.

Replacement Functions

If you have replacement versions of operator new and delete, they must match the signatures shown in "Exception Specifications", including the exception specifications on the functions. In addition, they must implement the same semantics. The normal forms of operator new must throw a bad_alloc exception on failure; the nothrow version must not throw any exception, but must return zero on failure. The forms of operator delete must not throw any exception. Code in the standard library uses the global operator new and delete and depends on this behavior for correct operation. Third-party libraries can have similar dependencies.

The global version of operator new[]() in the C++ 5.0 runtime library just calls the single-object version, operator new(), as required by the C++ standard. If you replace the global version of operator new() from the C++ 5.0 standard library, you don't need to replace the global version of operator new[] ().

The C++ standard prohibits replacing the predefined "placement" forms of operator new:

void* operator new(std::size_t, void*) throw();

void* operator new[](std::size_t, void*) throw();

They cannot be replaced in C++ 5.0 standard mode, although the 4.2 compiler allowed it. You can, of course, write your own placement versions with different parameter lists.

Header Inclusions

In compatibility mode, include <new.h> as always. In standard mode, include <new> (no .h) instead. To ease in transition, a header <new.h> is available in standard mode that makes the names from namespace std available in the global namespace. This header also provides typedefs that make the old names for exceptions correspond to the new exception names. See "Standard Exceptions".