As far as I know, the new
operator does the following things: (please correct me if I am wrong.)
I don't know about details in Java, but here is what new
and new[]
do in C++:
Allocate memory
When you have an expression new T
or new T(args)
, the compiler determines which function to call for getting memory
T
has an appropriate member operator new
that one is calledOtherwise, if the user provided an appropriate global operator new
that one is called.
If operator new
cannot allocate the requested memory, then it calls a new handler function, which you can set with set_new_handler
. That function may free some space so the allocation can succeed, it may terminate the program, or it may throw an exception of type std::bad_alloc
or derived from that. The default new handler just throws std::bad_alloc
.
The same happens for new T[n]
except that operator new[]
is called for memory allocation.
Construct the object resp. objects in the newly allocated memory.
For new T(args)
the corresponding constructor of the object is called. If the constructor throws an exception, the memory is deallocated by calling the corresponding operator delete
(which can be found in the same places as operator new
)
For new T
it depends if T
is POD (i.e. a built-in type or basically a C struct/union) or not. If T is POD, nothing happens, otherwise it is treated like new T()
.
For new T[n]
it also depends on whether T
is POD
. Again, PODs are not initialized. For non-PODs the default constructor is in turn called for each of the objects in order. If one object's default constructor throws, no further constructors are called, but the already constructed objects (which doesn't include the one whose constructor just threw) are destructed (i.e. have the destructor called) in reverse order. Then the memory is deallocated with the appropriate operator delete[]
.
Returns a pointer to the newly created object(s). Note that for new[]
the pointer will likely not point to the beginning of the allocated memory because there will likely be some information about the number of allocated objects preceding the constructed objects, which is used by delete[]
to figure out how many objects to destruct.
In all cases, the objects live until they are destroyed with delete ptr
(for objects allocated with normal new
) or delete[] ptr
(for objects created with array new T[n]
). Unless added with a third-party library, there's no garbage collection in C++.
Note that you also can call operator new
and operator delete
directly to allocate raw memory. The same is true for operator new[]
and operator delete[]
. However note that even for those low-level functions you may not mix the calls, e.g. by deallocating memory with operator delete
that you allocated with operator new[]
.
You can also copnstruct an object in allocated memory (no matter how you got that) with the so-called placement new. This is done by giving the pointer to the raw memory as argument to new
, like this: new(pMem) T(args)
. To destruct such an explicitly constructed object, you can call the object's destructor directly, p->~T()
.
Placement new works by calling an operator new
which takes the pointer as additional argument and just returns it. This same mechanism can also be used to provide other information to operator new
overloads which take corresponding additional arguments. However while you can define corresponding operator delete
, those are only used for cleaning up when an object throws an exception during construction. There's no "placement delete" syntax.
One other use of the placement new syntax which is already provided by C++ is nothrow new. That one takes an additional parameter std::nothrow
and differs from normal new
only in that it returns a null pointer if allocation fails.
Also note that new
is not the only memory management mechanism in C++. On the one hand, there are the C functions malloc
and free
. While usually operator new
and operator new[]
just call malloc
, this is not guaranteed. Therefore you may not mix those forms (e.g. by calling free
on a pointer pointing to memory allocated with operator new
). On the other hand, STL containers handle their allocations through allocators, which are objects which manage the allocation/deallocation of objects as well as construction/destruction of objects in containers.
And finally, there are those objects whose lifetime is controlled directly by the language, namely those of static and automatic lifetime. Automatic lifetime objects are allocated by simply defining a variable of the type at local scope. They are automatically created when execution passes that line, and automatically destroyed when execution leaves the scope (including it the scope is left through an exception). Static lifetime objects are define at global/namespace scope or at local scope using the keyword static. They are created at program startup (global/namespace scope) or when their definition line is forst executed (local scope), and they live until the end of the program, when they are automatically destroyed in reverse order of construction.
Generally, automatic or static variables are to be preferred to dynamic allocation (i,e, everything you allocate with new
or allocators), because there the compiler cares for proper destruction, unlike dynamic allocation where you have to do that on your own. If you have dynamically allocated objects, it's desirable to have their lifetime managed by automatic/static objects (containers, smart pointers) for the same reason.