Except for a form called the
"placement new", the operator denotes a request for memory allocation on a process's
heap. If sufficient memory is available, initialises the memory, calling object constructors if necessary, and returns the address to the newly allocated and initialised memory. A request, in its simplest form, looks as follows: T* p = new T; T* p = new T(); // zero-initialises primitives where is a
pointer of type (or some other type to which a pointer can be assigned, such as a
superclass of ). The
default constructor for , if any, is called to construct a instance in the allocated memory buffer. If not enough memory is available in the free store for an object of type , the request indicates failure by throwing an
exception of type . This removes the need to explicitly check the result of an allocation. The deallocation counterpart of is , which first calls the destructor (if any) on its argument and then returns the memory allocated by back to the free store. Every call to must be matched by a call to ; failure to do so causes a
memory leak.
JavaScript and
TypeScript have the operators new and delete. However, while new is used for calling the class constructor, delete does not call a destructor (as destructors do not exist in JavaScript or TypeScript). Instead, delete removes a property from an object. class User { name: string; age?: number; // marked optional to allow delete constructor(name: string, age?: number) { this.name = name; this.age = age; } } let user: User = new User("Alice", 30); delete user.age; // No TypeScript error // Output: { name: "Alice" } console.log(user); In C++, delete is also used to disable compiler-generated methods, such as default constructors. In
C++26, it is possible to provide a reason for its removal. class NonCopyable { public: NonCopyable() = default; NonCopyable(const NonCopyable&) = delete("No copy constructor"); NonCopyable& operator=(const NonCopyable&) = delete("No copy assignment"); };
Error handling If cannot find sufficient memory to service an allocation request, it can report its error in three distinct ways. Firstly, the
ISO C++ standard allows programs to register a custom function called a with the C++
runtime; if it does, then this function is called whenever encounters an error. The may attempt to make more memory available, or terminate the program if it can't. If no is installed, instead throws an
exception of type . Thus, the program does not need to check the value of the returned pointer, as is the habit in
C; if no exception was thrown, the allocation succeeded. The third method of error handling is provided by the variant form , which specifies that no exception should be thrown; instead, a
null pointer is returned to signal an allocation error.
Overloading The operator can be
overloaded so that specific types (classes) use custom memory allocation algorithms for their instances. For example, the following is a variant of the
singleton pattern where the first call allocates an instance and all subsequent calls return this same instance: import std; class Singleton { private: static void* instance = nullptr; static size_t refcount = 0; public: static void* operator new(size_t size) { if (!instance) { instance = std::malloc(size); } ++refcount; return instance; } static void operator delete(
maybe_unused void* p) noexcept { if (--refcount == 0) { std::free(instance); instance = nullptr; } } }; This feature was available from early on in C++'s history, although the specific overloading mechanism changed. It was added to the language because
object-oriented C++ programs tended to allocate many small objects with , which internally used the C allocator (see ); that, however, was optimized for the fewer and larger allocations performed by typical C programs.
Stroustrup reported that in early applications, the C function was "the most common performance bottleneck in real systems", with programs spending up to 50% of their time in this function. ==Relation to malloc and free==