You are on page 1of 17

6.

9 Dynamic memory allocation with new


and delete
By Alex on July 13th, 2007 | last modified by Alex on August 17th, 2016

The need for dynamic memory allocation

C++ supports three basic types of memory allocation, of which youve already seen two.

Static memory allocation happens for static and global variables. Memory for these
types of variables is allocated once when your program is run and persists throughout the
life of your program.

Automatic memory allocation happens for function parameters and local variables.
Memory for these types of variables is allocated when the relevant block is entered, and
freed when the block is exited, as many times as necessary.

Dynamic memory allocation is the topic of this article.

Both static and automatic allocation have two things in common:

The size of the variable / array must be known at compile time.

Memory allocation and deallocation happens automatically (when the variable is


instantiated / destroyed).

Most of the time, this is just fine. However, you will come across situations where one or both of
these constraints cause problems, usually when dealing with external (user or file) input.

For example, we may want to use a string to hold someones name, but we do not know how
long their name is until they enter it. Or we may want to read in a number of records from disk,
but we dont know in advance how many records there are. Or we may be creating a game, with
a variable number of monsters (that changes over time as some monsters die and new ones are
spawned) trying to kill the player.

If we have to declare the size of everything at compile time, the best we can do is try to make a
guess the maximum size of variables well need and hope thats enough:

1 char name[25]; // let's hope their name is less than 25 chars!


2 Record record[500]; // let's hope there are less than 500 records!
3 Monster monster[40]; // 40 monsters maximum
4 Polygon rendering[30000]; // this 3d rendering better not have more than 30,000 polygons!
This is a poor solution for at least four reasons:

First, it leads to wasted memory if the variables arent actually used. For example, if we allocate
25 chars for every name, but names on average are only 12 chars long, were using over twice
what we really need. Or consider the rendering array above: if a rendering only uses 10,000
polygons, we have 20,000 Polygons worth of memory not being used!

Second, how do we tell which bits of memory are actually used? For strings, its easy: a string
that starts with a \0 is clearly not being used. But what about monster[24]? Is it alive or dead
right now? That necessitates having some way to tell active from inactive items, which adds
complexity and can use up additional memory.

Third, most normal variables (including fixed arrays) are allocated in a portion of memory called
the stack. The amount of stack memory for a program is generally quite small -- Visual Studio
defaults the stack size to 1MB. If you exceed this number, stack overflow will result, and the
operating system will probably close down the program.

On Visual Studio, you can see this happen when running this program:

1 int main()
2 {
3 int array[1000000]; // allocate 1 million integers (probably 4MB of memory)
4 }

Being limited to just 1MB of memory would be problematic for many programs, especially those
that deal with graphics.

Fourth, and most importantly, it can lead to artificial limitations and/or array overflows. What
happens when the user tries to read in 600 records from disk, but weve only allocated memory
for a maximum of 500 records? Either we have to give the user an error, only read the 500
records, or (in the worst case where we dont handle this case at all) overflow the record array
and watch something bad happen.

Fortunately, these problems are easily addressed via dynamic memory allocation. Dynamic
memory allocation is a way for running programs to request memory from the operating system
when needed. This memory does not come from the programs limited stack memory -- instead,
it is allocated from a much larger pool of memory managed by the operating system called the
heap. On modern machines, the heap can be gigabytes in size.

Dynamically allocating single variables

To allocate a single variable dynamically, we use the scalar (non-array) form of the new
operator:

1 new int; // dynamically allocate an integer (and discard the result)


In the above case, were requesting an integers worth of memory from the operating system.
The new operator returns a pointer containing the address of the memory that has been allocated.

Most often, well assign the return value to our own pointer variable so we can access the
allocated memory later.

int *ptr = new int; // dynamically allocate an integer and assign the address to ptr so we can
1
access it later

We can then dereference the pointer to access the memory:

1 *ptr = 7; // assign value of 7 to allocated memory

If it wasnt before, it should now be clear at least one case in which pointers are useful. Without a
pointer to hold the address of the memory that was just allocated, wed have no way to access the
memory that was just allocated for us!

How does dynamic memory allocation work?

Your computer has memory (probably lots of it) that is available for applications to use. When
you run an application, your operating system loads the application into some of that memory.
This memory used by your application is divided into different areas, each of which serves a
different purpose. One area contains your code. Another area is used for normal operations
(keeping track of which functions were called, creating and destroying global and local variables,
etc). Well talk more about those later. However, much of the memory available just sits there,
waiting to be handed out to programs that request it.

When you dynamically allocate memory, youre asking the operating system to reserve some of
that memory for your programs use. If it can fulfill this request, it will return the address of that
memory to your application. From that point forward, your application can use this memory as it
wishes. When your application is done with the memory, it can return the memory back to the
operating system to be given to another program.

Unlike static or automatic memory, the program itself is responsible for requesting and disposing
of dynamically allocated memory.

Initializing a dynamically allocated variable

When you dynamically allocate a variable, you can also initialize it via direct initialization or
uniform initialization (in C++11):

1 int *ptr1 = new int (5); // use direct initialization


2 int *ptr2 = new int { 6 }; // use uniform initialization

Deleting single variables


When we are done with a dynamically allocated variable, we need to explicitly tell C++ to free
the memory for reuse. For single variables, this is done via the scalar (non-array) form of the
delete operator:

1 // assume ptr has previously been allocated with operator new


2 delete ptr; // return the memory pointed to by ptr to the operating system
3 ptr = 0; // set ptr to be a null pointer (use nullptr instead of 0 in C++11)

What does it mean to delete memory?

The delete operator does not actually delete anything. It simply returns the memory being
pointed to back to the operating system. The operating system is then free to reassign that
memory to another application (or to this application again later).

Although it looks like were deleting a variable, this is not the case! The pointer variable still has
the same scope as before, and can be assigned a new value just like any other variable.

Note that deleting a pointer that is not pointing to dynamically allocated memory may cause bad
things to happen.

Dangling pointers

C++ does not make any guarantees about what will happen to the contents of deallocated
memory, or to the value of the pointer being deleted. In most cases, the memory returned to the
operating system will contain the same values it had before it was returned, and the pointer will
be left pointing to the now deallocated memory.

A pointer that is pointing to deallocated memory is called a dangling pointer. Dereferencing or


deleting a dangling pointer will lead to undefined behavior. Consider the following program:

1 #include <iostream>
2
3 int main()
4 {
5 int *ptr = new int; // dynamically allocate an integer
6 *ptr = 7; // put a value in that memory location
7
8 delete ptr; // return the memory to the operating system. ptr is now a dangling pointer.
9
10 std::cout << *ptr; // Dereferencing a dangling pointer will cause undefined behavior
11 delete ptr; // trying to deallocate the memory again will also lead to undefined behavior.
12
13 return 0;
14 }
In the above program, the value of 7 that was previously assigned to the allocated memory will
probably still be there, but its possible that the value at that memory address could have
changed. Its also possible the memory could be allocated to another application (or for the
operating systems own usage), and trying to access that memory will cause the operating system
to shut the program down.

Deallocating memory may create multiple dangling pointers. Consider the following example:

#include <iostream>
1
2
int main()
3
{
4
int *ptr = new int; // dynamically allocate an integer
5
int *otherPtr = ptr; // otherPtr is now pointed at that same memory location
6
7
delete ptr; // return the memory to the operating system. ptr and otherPtr are now dangling
8
pointers.
9
ptr = 0; // ptr is now a nullptr
10
11
// however, otherPtr is still a dangling pointer!
12
13
return 0;
14
}

Rule: To avoid dangling pointers, after deleting memory, set all pointers pointing to the deleted
memory to 0 (or nullptr in C++11).

Operator new can fail

When requesting memory from the operating system, in rare circumstances, the operating system
may not have any memory to grant the request with.

By default, if new fails, a bad_alloc exception is thrown. If this exception isnt properly handled
(and it wont be, since we havent covered exceptions or exception handling yet), the program
will simply terminate (crash) with an unhandled exception error.

In many cases, having new throw an exception (or having your program crash) is undesirable, so
theres an alternate form of new that can be used instead to tell new to return a null pointer if
memory cant be allocated. This is done by adding the constant std::nothrow between the new
keyword and the allocation type:

int *value = new (std::nothrow) int; // value will be set to a null pointer if the integer allocation
1
fails

In the above example, if new fails to allocate memory, it will return a null pointer instead of the
address of the allocated memory.
Note that if you then attempt to dereference this memory, your program will crash. Consequently,
the best practice is to check all memory requests to ensure they actually succeeded before using
the allocated memory.

1 int *value = new (std::nothrow) int; // ask for an integer's worth of memory
2 if (!value) // handle case where new returned null
3 {
4 std::cout << "Could not allocate memory";
5 exit(1);
6 }

Because asking new for memory only fails rarely (and almost never in a dev environment), its
common to forget to do this check!

Null pointers and dynamic memory allocation

Null pointers (pointers set to address 0 or nullptr) are particularly useful when dealing with
dynamic memory allocation. In the context of dynamic memory allocation, a null pointer
basically says no memory has been allocated to this pointer. This allows us to do things like
conditionally allocate memory:

1 // If ptr isn't already allocated, allocate it


2 if (!ptr)
3 ptr = new int;

Deleting a null pointer has no effect. Thus, there is no need for the following:

1 if (ptr)
2 delete ptr;

Instead, you can just write:

1 delete ptr;

If ptr is non-null, the dynamically allocated variable will be deleted. If it is null, nothing will
happen.

Memory leaks

Dynamically allocated memory effectively has no scope. That is, it stays allocated until it is
explicitly deallocated or until the program ends (and the operating system cleans it up, assuming
your operating system does that). However, the pointers used to hold dynamically allocated
memory addresses follow the scoping rules of normal variables. This mismatch can create
interesting problems.
Consider the following function:
1 void doSomething()
2 {
3 int *ptr = new int;
4 }

This function allocates an integer dynamically, but never frees it using delete. Because pointers
follow all of the same rules as normal variables, when the function ends, ptr will go out of scope.
Because ptr is the only variable holding the address of the dynamically allocated integer, when
ptr is destroyed there are no more references to the dynamically allocated memory. This is called
a memory leak. As a result, the dynamically allocated integer can not be deleted, and thus can
not be reallocated or reused while the program is running. Memory leaks eat up free memory
while the program is running, making less memory available not only to this program, but to
other programs as well. Programs with severe memory leak problems can eat all the available
memory, causing the entire machine to run slowly or even crash.

Memory leaks can also result if the pointer holding the address of the dynamically allocated
memory is reassigned to another value:

1 int value = 5;
2 int *ptr = new int; // allocate memory
3 ptr = &value; // old address lost, memory leak results

It is also possible to get a memory leak via double-allocation:

1 int *ptr = new int;


2 ptr = new int; // old address lost, memory leak results

The address returned from the second allocation overwrites the address of the first allocation.
Consequently, the first allocation becomes a memory leak!

Conclusion

Operators new and delete allow us to dynamically allocate single variables for our programs.

Dynamically allocated memory has no scope and will stay allocated until you deallocate it or the
program terminates.

Be careful not to dereference dangling or null pointers.

In the next lesson, well take a look at using new and delete to allocate and delete arrays.
Class members that are objects - Pointers or
not? C++
Ask Question

If I create a class MyClass and it has some private member say MyOtherClass, is it
better to make MyOtherClass a pointer or not? What does it mean also to have it as
not a pointer in terms of where it is stored in memory? Will the object be created
when the class is created?

I noticed that the examples in QT usually declare class members as pointers when
they are classes.
up vote 20
down vote Regards
favorite
13 Mark

c++ memory pointers class-design member


edited Oct 6 '10 at 10:29 asked Oct 6 '10 at 10:11

shareedit

rursw1 Mark
2,31122661 66631326
1 Code is better than English as a description. Loki Astari Oct 6 '10 at 11:55
add a comment

11 Answers
active oldest votes
up vote 23
down vote If I create a class MyClass and it has some private member say MyOtherClass, is it
accepted better to make MyOtherClass a pointer or not?

you should generally declare it as a value in your class. it will be local, there will be
less chance for errors, fewer allocations -- ultimately fewer things that could go
wrong, and the compiler can always know it is there at a specified offset so... it
helps optimization and binary reduction at a few levels. there will be a few cases
where you know you'll have to deal with pointer (i.e. polymorphic, shared, requires
reallocation), it is typically best to use a pointer only when necessary - especially
when it is private/encapsulated.
What does it mean also to have it as not a pointer in terms of where it is stored in
memory?

its address will be close to (or equal to) this -- gcc (for example) has some
advanced options to dump class data (sizes, vtables, offsets)

Will the object be created when the class is created?

yes - the size of MyClass will grow by sizeof(MyOtherClass), or more if the


compiler realigns it (e.g. to its natural alignment)

answered Oct 6 '10 at 10:35

shareedit

justin
91.3k10146193
The big downside to this in larger projects is it forces a #include of the header
where MyOtherClass is declared. This can quickly lead to very slow
8
compilation times. If you use a (smart) pointer, you can get away with a
forward declaration. Ben Oct 7 '10 at 19:26
@Ben +1 yes - i failed to mention intermodule dependencies and abstraction of
them in my post. this is a very important reason to favor dynamically allocated
members in some cases. justin Oct 8 '10 at 5:08
add a comment
up vote 19
down vote Where is your member stored in memory?
Take a look at this example:

struct Foo { int m; };


struct A {
Foo foo;
};
struct B {
Foo *foo;
B() : foo(new Foo()) { } // ctor: allocate Foo on heap
~B() { delete foo; } // dtor: Don't forget this!
};

void bar() {
A a_stack; // a_stack is on stack
// a_stack.foo is on stack too
A* a_heap = new A(); // a_heap is on stack (it's a pointer)
// *a_heap (the pointee) is on heap
// a_heap->foo is on heap
B b_stack; // b_stack is on stack
// b_stack.foo is on stack
// *b_stack.foo is on heap
B* b_heap = new B(); // b_heap is on stack
// *b_heap is on heap
// b_heap->foo is on heap
// *(b_heap->foo is on heap
delete a_heap;
delete b_heap;
// B::~B() will delete b_heap->foo!
}

We define two classes A and B. A stores a public member foo of type Foo. B has a
member foo of type pointer to Foo.

What's the situation for A:

If you create a variable a_stack of type A on the stack, then the object
(obviously) and its members are on the stack too.

If you create a pointer to A like a_heap in the above example, just the pointer
variable is on the stack; everything else (the object and it's members) are on
the heap.

What does the situation look like in case of B:

you create B on the stack: then both the object and its member foo are on the
stack, but the object that foo points to (the pointee) is on the heap. In short:
b_stack.foo (the pointer) is on the stack, but *b_stack.foo the (pointee)
is on the heap.

you create a pointer to B named b_heap: b_heap (the pointer) is on the stack,
*b_heap (the pointee) is on the heap, as well as the member b_heap->foo
and *b_heap->foo.

Will the object be automagically created?


In case of A: Yes, foo will automatically be created by calling the implicit
default constructor of Foo. This will create an integer but will not
intitialize it (it will have a random number)!

In case of B: If you omit our ctor and dtor then foo (the pointer) will also be
created and initialized with a random number which means that it will point
to a random location on the heap. But note, that the pointer exists! Note
also, that the implicit default constructor won't allocate something for foo
for you, you have to do this explicitly. That's why you usually need an
explicit constructor and a accompanying destructor to allocate and delete
the pointee of your member pointer. Don't forget about copy semantics:
what happens to the pointee if your copy the object (via copy construction or
assignment)?

What's the point of all of this?


There are several use cases of using a pointer to a member:

To point to an object you don't own. Let's say your class needs access to a
huge data structure that is very costly to copy. Then you could just save a
pointer to this data structure. Be aware that in this case creation and
deletion of the data structure is out of the scope of your class. Someone
other has to take care.

Increasing compilation time, since in your header file the pointee does not
have to be defined.

A bit more advanced; When your class has a pointer to another class that
stores all private members, the "Pimpl idiom": http://c2.com/cgi/wiki?
PimplIdiom, take also a look at Sutter, H. (2000): Exceptional C++, p. 99--
119

And some others, look at the other answers

Advice
Take extra care if your members are pointers and you own them. You have to write
proper constructors, destructors and think about copy constructors and assignment
operators. What happens to the pointee if you copy the object? Usually you will
have to copy construct the pointee as well!

answered Oct 6 '10 at 11:05

shareedit edited Oct 6 '10 at 11:43

WolfgangA
2,2781732
I don't find thinking in terms of heap/stack very usefull (especially since neither
are really defined by the standard). I think of objects in terms of their lifespan
in relation to the containing block. An object with a scoped life should be an
object. An object that has a dynamic lifespan should be a pointer (stored in a
smart pointer). The only different between a member variable and a function
variable is their scope. A member variables lifespan is relative to its scope the
object that it resides in. While a function variables is relative to its scope the
function (or block). Loki Astari Oct 6 '10 at 12:03
That's definitly true, but the question was where the objects are stored in
memory, which is useful to sort things out in your head. WolfgangA Oct 6 '10
at 12:08
add a comment

In C++, pointers are objects in their own right. They're not really tied to whatever they
point to, and there's no special interaction between a pointer and its pointee (is that a
word?)

If you create a pointer, you create a pointer and nothing else. You don't create the
object that it might or might not point to. And when a pointer goes out of scope, the
pointed-to object is unaffected. A pointer doesn't in any way affect the lifetime of
whatever it points to.

up vote So in general, you should not use pointers by default. If your class contains another
15 down object, that other object shouldn't be a pointer.
vote
However, if your class knows about another object, then a pointer might be a good
way to represent it (since multiple instances of your class can then point to the same
instance, without taking ownership of it, and without controlling its lifetime)

answered Oct 6 '10 at 10:19

shareedit

jalf
185k36262497
On the other hand, PIMPL is all about cutting down the dependencies by
2 introducing a layer of indirection in the visibility. Matthieu M. Oct 6 '10 at
12:19
add a comment
up vote 5
down The common wisdom in C++ is to avoid the use of (bare) pointers as much as
vote possible. Especially bare pointers that point to dynamically allocated memory.

The reason is because pointers make it more difficult to write robust classes,
especially when you also have to consider the possibility of exceptions being thrown.

shareedit answered Oct 6 '10 at 10:23


Bart van Ingen Schenau
11.6k22032
add a comment

I follow the following rule: if the member object lives and dies with the encapsulating
object, do not use pointers. You will need a pointer if the member object has to outlive
the encapsulating object for some reason. Depends on the task at hand.

Usually you use a pointer if the member object is given to you and not created by you.
up vote 3 Then you usually don't have to destroy it either.
down
vote answered Oct 6 '10 at 10:29

shareedit

chvor
62464
add a comment
up vote 3
down Some advantages of pointer member:
vote
The child (MyOtherClass) object can have different lifetime than its parent
(MyClass).

The object can possibly be shared between several MyClass (or other) objects.

When compiling the header file for MyClass, the compiler doesn't necessarily
have to know the definition of MyOtherClass. You don't have to include its
header, thus decreasing compile times.

Makes MyClass size smaller. This can be important for performance if your
code does a lot of copying of MyClass objects. You can just copy the
MyOtherClass pointer and implement some kind of reference counting system.

Advantages of having the member as an object:

You don't have to explicitely write code to create and destroy the object. It's
easier and and less error-prone.

Makes memory management more efficient because only one block of


memory needs to be allocated instead of two.

Implementing assignment operators, copy/move constructors etc is much


simpler.

More intuitive

answered Oct 6 '10 at 11:01

shareedit

Timo
3,79731622
add a comment

This question could be deliberated endlessly, but the basics are:

If MyOtherClass is not a pointer:

The creation and destruction of MyOtherClass is automatic, which can reduce


bugs.

The memory used by MyOtherClass is local to the MyClassInstance, which


could improve performance.

If MyOtherClass is a pointer:
up vote 3
down vote The creation and destruction of MyOtherClass is your responsibility

MyOtherClass may be NULL, which could have meaning in your context and
could save memory

Two instances of MyClass could share the same MyOtherClass

answered Oct 6 '10 at 10:24

shareedit

Drew Dormann
35.4k965125
add a comment
up vote 1
down An advantage of the parent class maintaining the relation to a member object as a
vote (std::auto_ptr) pointer to the member object is that you can forward declare the object
rather than having to include the object's header file.

This decouples the classes at build time allowing to modify the member object's
header class without causing all the clients of your parent class to be recompiled as
well even though they probably do not access the member object's functions.

When you use an auto_ptr, you only need to take care of construction, which you
could typically do in the initializer list. Destruction along with the parent object is
guaranteed by the auto_ptr.

answered Oct 6 '10 at 11:26

shareedit

andreas buykx
6,41664072
add a comment
up vote 1
down vote It depends... :-)

If you use pointers to say a class A, you have to create the object of type A e.g. in
the constructor of your class

m_pA = new A();

Moreover, don't forget to destroy the object in the destructor or you have a memory
leak:

delete m_pA;
m_pA = NULL;

Instead, having an object of type A aggregated in your class is easier, you can't forget
to destroy it, because this is done automatically at the end of lifetime of your object.

On the other hand, having a pointer has the following advantages:

If your object is allocated on the stack and type A uses a lot of memory this
won't be allocated from the stack but from the heap.

You can construct your A object later (e.g. in a method Create) or destroy it
earlier (in method Close)

shareedit answered Oct 6 '10 at 10:29


ur.
2,51311117
add a comment

If you make the MyOtherClass object as member of your MyClass:

size of MyClass = size of MyClass + size of MyOtherClass

If you make the MyOtherClass object as pointer member of your MyClass:

size of MyClass = size of MyClass + size of any pointer on your


system

up vote 1 You might want to keep MyOtherClass as a pointer member because it gives you the
down vote flexibility to point it to any other class that is derived from it. Basically helps you
implement dynamice polymorphism.

answered Oct 6 '10 at 10:23

shareedit

Alok Save
145k26295439
add a comment
up vote 0
down The simple thing to do is to declare your members as objects. This way, you do not
vote have to care about copy construction, destruction and assignment. This is all taken
care of automatically.

However, there are still some cases when you want pointers. After all, managed
languages (like C# or Java) actually hold member objects by pointers.

The most obvious case is when the object to be kept is polymorphic. In Qt, as you
pointed out, most objects belong to a huge hierarchy of polymorphic classes, and
holding them by pointers is mandatory since you don't know at advance what size will
the member object have.

Please beware of some common pitfalls in this case, especially when you deal with
generic classes. Exception safety is a big concern:

struct Foo
{
Foo()
{
bar_ = new Bar();
baz_ = new Baz(); // If this line throw, bar_ is never
reclaimed
// See copy constructor for a workaround
}

Foo(Foo const& x)
{
bar_ = x.bar_.clone();
try { baz_ = x.baz_.clone(); }
catch (...) { delete bar_; throw; }
}

// Copy and swap idiom is perfect for this.


// It yields exception safe operator= if the copy constructor
// is exception safe.
void swap(Foo& x) throw()
{ std::swap(bar_, x.bar_); std::swap(baz_, x.baz_); }

Foo& operator=(Foo x) { x.swap(*this); return *this; }

private:
Bar* bar_;
Baz* baz_;
};

As you see, it is quite cumbersome to have exception safe constructors in the presence
of pointers. You should look at RAII and smart pointers (there are plenty of resources
here and somewhere else on the web).

You might also like