new
do more than allocate memory?Yes, it also initializes the new object.
Assuming Fred
is a known type, the expression new Fred()
is a two-step operation. The first step is to allocate sizeof(Fred)
bytes of memory using a memory allocator primitive called operator new(size_t nbytes
) (size_t
is a typedef
for an unsigned
integral type such as unsigned int
). This memory allocation primitive is conceptually similar to but not interchangeable with malloc(size_t nbytes)
. The second step is to call the appropriate constructor of the class (Fred::Fred()
in this case).
Similarly, delete p
is a two-step operation: it first calls the destructor on the object *p
, then it releases the memory pointed to by p
using a memory deallocation primitive. This memory deallocation primitive is called operator delete(void* p
) and is conceptually similar to but not interchangeable with free(void* p
).
new
better than good old trustworthy malloc()
?It does more.
Object construction: In C++, new
and delete
create and destroy objects. In contrast, malloc()
and free()
merely allocate and deallocate memory.
Safety: The new
operator returns a pointer of the correct type whereas the function malloc()
returns a void*
, which isn't type safe. The C language allows a void*
to be converted to any other pointer, but this is a dangerous hole in C's type-checking system. C++ doesn't have this weakness: converting a void*
to a different pointer type requires an explicit cast in C++.
Flexibility: The new
operator can be overloaded by a class. For example, new Fred()
can use a different memory allocation primitive than is used by new Wilma()
. In contrast, malloc()
cannot be overloaded on a class-by-class basis.
realloc()
that goes along with new
and delete
? No; and don't use realloc()
directly, since bitwise copying of an object of a user-defined class is evil.
When realloc()
needs to move data during the reallocation, it uses a bitwise copy, which is disastrous for many user-defined classes (see FAQ 30.15). C++ objects know how to copy themselves using their own copy constructors and assignment operators.
Never use realloc()
on objects of user-defined classes. Let the objects copy themselves. Better yet, use the vector
template class rather than pointers to arrays, and the vector
template will take care of reallocation automatically and correctly (see FAQ 28.13).
new
be deallocated with free()
? Can pointers returned from malloc()
be deallocated with delete
?No!
It is perfectly legal, moral, and wholesome to use malloc()
and delete
in the same program or to use new
and free()
in the same program. But it is illegal, immoral, and despicable to call free()
on a pointer allocated via new
or to call delete
on a pointer allocated via malloc()
.
Even if it appears to work on your particular compiler on your particular machine, please don't do it. Corrupting the heap is a very subtle and disastrous thing; it's just not worth the trouble—even if the data type is a simple array of char
; even if some programmers think it would be cool. Just say no.
delete p
delete the pointer p
or the referent *p
?The referent *p
.
If verbosity were a virtue, the syntax would be changed from delete p
to deleteTheThingPointedToBy p
. One could argue that the current syntax is misleading, but the same abuse of English occurs with free(p)
from the C language: free(p)
doesn't free p
; rather it frees the memory pointed to by p
.
new Fred()
be checked to see if it is NULL
? No, new Fred()
never ever returns NULL
. Instead, if new
runs out of memory during new Fred()
, it throws an exception of type bad_alloc
(see FAQ 9.02).
Because of this, the if
test in the following example is considered bad form since it increases code size, increases code complexity, and increases testing costs, yet it adds no value (remember, exceptions guarantee that p
will never be NULL
).
C programmers please note that this behavior is very different from the way out-of-memory is handled by malloc()
. To be safe, every call to malloc()
has to be followed by an explicict if
test to see if malloc()
returned NULL
.
new
be convinced to return NULL
rather than throw an exception? Replace new Fred()
with new(nothrow) Fred()
. Note that this is a step backward for the reasons already described, so this technique should not be extensively used in new C++ code. However this technique is relevant for people who have to deal with C++ software that was written before new Fred()
threw exceptions.
When preexception C++ code is compiled on a modern C++ compiler, the use of exceptions may cause the application to crash. In this case, there are two basic options: update the application by making it exception safe (that is, make the code do something reasonable even if something such as new
throws an exception), or patch the application by replacing new Fred()
with new(nothrow) Fred()
. Often, but not always, it is cheaper to patch it rather than make it exception safe. The following example demonstrates this technique.
new
be set up to automatically flush pools of recycled objects whenever memory runs low?
Applications that do a lot of freestore allocations can sometimes improve performance by using global pools of recycled objects. For example, when a dynamically allocated Fred
object is no longer needed, the programmer can say p->discard()
rather than delete p
, and the discard()
member function adds the object to a static
pool of Fred
objects. Then when a Fred
object is needed, the programmer says Fred::create()
rather than new Fred()
, and the static create()
member function returns the first entry from the list (or returns new Fred()
if the list is empty).
Everything works great until memory runs low, at which point the pool of Fred
objects needs to be flushed to free up available memory. It would be ideal if the runtime system would automatically call some routine such as Fred::flushPool()
whenever new
ran low on memory, since the pool could be flushed without any functional impact. For example, if someone wants to create a Wilma
object and the system runs out of memory because there are too many recycled Fred
objects in the Fred
pool, the goal is to have the system automatically call Fred::flushPool()
, which actually deletes all the Fred
objects on the recycled list. We set up the Fred
class with its pool of recycled objects:
First, notice how users are prevented from saying new Fred()
or delete p
. Instead users must say Fred::create()
and p->discard()
, respectively. The discard()
member function adds the object to the recycled pool, and the create()
static member function uses the recycled pool if it isn't empty. Finally the flushPool()
static member function flushes the pool of recycled Fred
objects, and returns a bool
indicating whether anything actually was deleted.
Next, to acomplish the larger goal of having the system automatically call Fred::flushPool()
whenever new
runs out of memory, a special function is created that calls Fred::flushPool()
(and possibly other similar pools, such as Wilma::flushPool()
). This special function is known as a new handler and is called flushAllPools()
in the following example. If operator new(size_t nbytes
) runs out of memory, it calls this function, which tries to delete some unneeded memory. If the new handler succeeds at freeing up some storage, it simply returns to operator new(size_t nbytes
), and operator new(size_t nbytes
) tries the allocation again. If the new handler is unsuccessful at freeing up storage, it avoids an infinite loop by throwing an exception:
The final step is to register the function flushAllPools()
as the official new handler. This is done using the set_new_handler()
function and is normally called very early in the application's execution:
The rest is automatic: if someone says new Barney()
and the underlying allocator (operator new(size_t nbytes)
) runs out of memory, the allocator automatically calls the new handler (flushAllPools()
), which flushes the Fred
pool (Fred::flushPool()
). If something actually was flushed, the new handler returns to operator new(size_t)
, which tries again. If it fails a second time, the whole process repeats. Eventually one of two things happens: either operator new(size_t)
succeeds, in which case the caller who said new Barney()
will never know that any of this ever happened, or flushAllPools()
fails to flush anything and throws an exception (in which case the new Barney()
attempt vanishes, and control goes to the appropriate catch
handler; see FAQ 9.03). In either case, the users who are saying new Barney()
don't know anything about the pool mechanism—it is invisible to them.
delete p
is called when p
is NULL
?Nothing.
Calling delete p
when p
is NULL
is safe and is guaranteed to do nothing. This simplifies code that uses delete
by letting programmers say delete p
; rather than if (p != NULL) delete p
;. For example,
There are two problems with the explicit if
test: first, some people get the test backwards (e.g., they say if (!p) delete p;
which is backward), and second, if
tests significantly increase the cost of testing—to achieve branch point coverage, both the “if true” and the “if false” branches of every if
need to be exercised. Thus, adding unnecessary branch points, such as if
statements, to an application causes the creation of unnecessary test cases. Conversely, if a branch point can be removed from the software without complicating or invalidating something else, in general the expected quality of the software goes up and the testing cost goes down.
Catastrophe.
Suppose there is a pointer variable p
. The first time delete p
is executed, the object *p
is safely destructed and the memory pointed to by p
is safely returned to the heap. The second time the same pointer is passed to delete
without a subsequent new
that returned that pointer, the remains of what used to be an object at *p
are passed to the destructor (which could be disastrous), and the memory pointed to by p
is handed back to the heap a second time. This is likely to corrupt the heap and its list of free memory. The following example illustrates this situation.
The best way is to be radical. Instead of trying to use an array pointer correctly, it is easier (and often more efficient) not to use explicit pointers at all but instead to use a container template such as vector
(see FAQ 28.13). Please don't use explicit pointers unless it is necessary. Pointers are a source of a lot of errors; using a good container class library can eliminate many pointer errors.
If it is necessary or desired to use pointers anyway, the right way to allocate an array of things is with p = new Fred[n]
. When the array is deallocated, the []
must appear just after the delete
keyword, such as delete[] p;
. Here is an example.
The purpose of the syntactic difference between delete p
and delete[] p
is to distinguish deleting a thing from deleting an array of things. This is because there is no syntactic difference between the type “pointer to a thing” (Fred*
) and the type “pointer to the first element of an array of things” (Fred*
). This is a feature that C++ inherited from C.
After all this, recall that the real solution is to not use pointers at all but instead to use a good container class library. For example, when an array of things is needed, use a container class that implements an array of things, such as the standard template vector
(see FAQ 28.13).
delete p
(not delete[] p
) is used to delete an array allocated via new Fred[n]
?Catastrophe.
It is the programmer's responsibility—not the compiler's—to verify that the connection between new[]
and delete[]
is correct. If it is wrong, don't expect either a compiler error message or a clean runtime exception. Expect a disaster. Worse, the disaster might not show up during testing; it might not show up until after the software is in the field.
For example, some implementations immediately corrupt the heap when the []
is omitted when deleting an array of objects; other implementations fail to destruct all but the first object in the array. The latter could cause memory leaks if the destructors release memory, cause deadlock if the destructors unlock semaphores, compromise system integrity in other ways, or trigger some combination of any or all of these.
Remember that this headache can be instantly eliminated if container classes, such as vector
, are used instead of raw pointers. Please use raw pointers only when it's absolutely necessary.
[]
of delete[] p
be dropped when p
points to an array of some built-in type such as char
?No; there is no reason to do this and it risks an avoidable disaster.
Some programmers tragically think that the []
in the delete[] p
exists only so that the compiler will call the appropriate number of destructors. Following this reasoning, they assume that the []
are optional when the array is of some built-in type such as an array of char
:
The delete p;
line above is wrong, and it can cause a disaster at runtime. In particular, the underlying deallocation primitive called for delete p
; is operator delete(void*)
, but the deallocation primitive called for delete[] p
; is operator delete[](void*)
. The default behavior for the latter is to call the former, but users are allowed to replace the latter with a different behavior. For example, someone might replace operator new[](size_t)
(the allocation primitive called for new char[n]
) and operator delete[](void*)
with a separate heap from operator new(size_t)
and operator delete(void*)
. If that happens, the delete p;
line sends the pointer to the wrong heap, which could result in a disaster at runtime.
Remember: use container classes rather than raw pointers. This example could use the standard string
class or perhaps something like the standard vector
template.
With the placement syntax of the new
operator, also known as placement new.
Objects are normally created on the stack, on the heap, or in static memory. These correspond to automatic allocation, dynamic allocation, and static allocation, respectively. But these normal techniques don't allow the programmer to specify the exact address at which the object will live.
Occasionally an object's desired location is known before the object is created, such as when the hardware uses a piece of storage as a way of communicating with the software. In these cases, placement new can be used.
The following example places an object of class Fred
at the hexadecimal address 0xFEEDBABE
and passes (42, 42)
to the Fred
constructor.
The storage pointed to by place
must be large enough to hold sizeof(Fred)
bytes and must be properly aligned to hold a Fred object
. The returned pointer p
is numerically the same as place
, but p
is a Fred*
rather than a void*
.
Fred
guarantee that Fred
objects are created only with new
and not on the stack? The class can make all of its constructors private:
or protected:
and can provide static create()
member functions. The copy constructor should also be made private:
or protected:
, even if it doesn't need to be defined otherwise (see FAQ 30.06). The static
(or friend
) create()
functions then create the object using new
and return a pointer to the allocated object. Here's an example.
Note that derived classes can't be instantiated since all of the constructors are private:
. Derived classes could be instantiated only if some of the constructors were protected:
.
new
destroyed?By explicitly calling the object's destructor. This is about the only time a destructor is called explicitly (see FAQ 20.10). For example, if p
is a Fred*
that was returned from placement new
, *p
can be destructed as follows.
Caution: Do not explicitly call the destructor of an object that will later be automatically destroyed, such as an object on the stack, an object on the heap that will be delete
d, or a static
object. The only time a destructor should be called explictly is when the programmer is in total control of the storage allocation and lifetime of the object—in other words, only with objects initialized by the placement new
syntax.
p = new Fred()
, does the Fred
memory “leak” if the Fred
constructor throws an exception?No, the system straightens things out automatically.
If an exception occurs in the Fred
constructor during p = new Fred()
, the sizeof(Fred)
bytes that were allocated are automatically released back to the heap. This is because new Fred()
is a two-step process.
sizeof(Fred)
bytes of memory are allocated using the memory allocation primitive void* operator new(size_t nbytes)
. This primitive is similar in spirit to malloc(size_t nbytes)
(however operator new(size_t)
and malloc(size_t)
are not interchangeable; the two memory allocation primitives may not even use the same heap!). Recall that size_t
is a typedef
for some unsigned integral type such as unsigned int
. Many system headers cause this typedef
to be defined.Fred
object is constructed in the returned memory location by calling the Fred
constructor. Thus the pointer returned from the first step is passed as the constructor's this
parameter. The call to the constructor is conceptually wrapped in a try
block so that the memory can be released if the constructor throws an exception.Thus the compiler generates code that looks something like that shown in following function sample()
.
The statement new(p) Fred();
is called the placement new
syntax (see FAQ 12.14). The effect is to call the Fred
constructor, passing the pointer p
as the constructor's this
parameter.
delete this
?Yes, but be careful.
Programmers usually have a hard time emotionally accepting that this is valid, probably because it seems as if the member function is inside the object and deleting the object during a member function seems strange. But with care, this technique can be perfectly safe. Here is how we define “with care.”
this
object must have been allocated via new
(see FAQ 12.15), not by new[]
(see FAQ 12.11) nor by placement new
(see FAQ 12.14) nor by a local object on the stack nor by a global nor by a member of another object. It has to have been allocated by plain, ordinary new
.delete this;
must be the last member function that is invoked on the this
object.delete this;
line must not touch any piece of the this
object, including calling any other member functions or touching any data members.this
pointer itself after the delete this;
line. No one may examine it, compare it with another pointer, compare it with NULL
, print it, cast it, do anything with it.delete
on the object. For example, if the object is still being held by an auto_ptr
(which would be a good thing!), the release()
member function must be called on the auto_ptr
; otherwise the auto_ptr
will delete
the object again, which would be a disaster. For example:
p = new Fred[n]
, how does the compiler know that there are n
objects to be destructed during delete[] p
?Warning: This FAQ is quite low level. The only people who really need to worry about this level of detail are those in extremely performance sensitive situations where CPU cycles are at a premium. Of course it also might be interesting to those who are just plain curious...
Whenever someone says Fred* p = new Fred[n]
, the runtime system is required to store the number of objects, n
, in a place that can be retrieved knowing only the pointer, p
. The compiler can use any technique it wants to use, but there are two popular ones.
p = new Fred[n]
might store the number n
in a static associative array, where the pointer p
is used as the lookup key and the number n
is the associated value. For example, using the standard map
template (see FAQ 28.14), this associative array might be map<void*,size_t>
. The code generated by delete[] p
would look up the pointer in the associative array, would extract the associated size_t
, then would remove the entry from the associative array.p = new Fred[n]
might allocate an extra sizeof(size_t)
bytes of memory (possibly plus some alignment bytes) and put the value n
just before the first Fred
object. Then delete[] p
would find n
by looking at the fixed offset before the first Fred
object (that is, before *p
) and would deallocate the memory starting at the beginning of the allocation (that is, the block of memory beginning the fixed offset before *p
).Neither technique is perfect. Here are a few of the tradeoffs.
[]
when deallocating an array of things, (a) the entry in the associative array would be a leak, and (b) only the first object in the array would be destructed. This may or may not be a serious problem, but at least it might not crash the application.delete p
where they should have said delete[] p
, the address that is passed to operator delete(void* p)
would not be a valid heap allocation—it would be at least sizeof(size_t)
bytes after a valid heap allocation. This would probably corrupt the heap. Bang, you're dead.