Show Lecture.DynamicMemory as a slide show.
CS253 Dynamic Memory
The old C way
In C, we used functions to allocate & free memory:
They still work, but don’t use them. They’re not type-safe,
and they don’t call ctors & dtors (constructors and destructors).
The new C++ way
In C++, we use keywords to allocate & free memory:
You have to delete the memory that you allocate.
Don’t delete it more than once!
Scalar Example
int *p = new int;
*p = 42;
cout << p << ' ' << *p << '\n';
delete p;
0x13e02b0 42
Array Example
int *a = new int[10];
for (int i=0; i<10; i++)
a[i] = i*11;
for (int i=0; i<10; i++)
cout << a[i] << ',';
delete[] a; // Note the []
0,11,22,33,44,55,66,77,88,99,
- For every call to
new
, you must call delete
.
- For every call to
new
[]
, you must call delete
[]
.
If you mix them up, the system might catch your error,
or it might not.
Java Error
Java programmers, remember that objects do not have to be
dynamically allocated. You can, but you don’t have to.
string s = new string;
c.cc:1: error: conversion from 'std::__cxx11::string*' {aka
'std::__cxx11::basic_string<char>*'} to non-scalar type
'std::__cxx11::string' {aka 'std::__cxx11::basic_string<char>'} requested
Instead, just declare the string:
string s = "Hi there\n";
cout << s;
Hi there
Sure, the string allocates dynamic memory, internally, but that’s
none of your business.
Avoid all of this
In general, use standard containers such as string
,
vector
, or list
when you can. They handle the dynamic
memory allocation, so you don’t have to.
Besides, code that deals with dynamic memory is easy to get wrong.
Code that you write will have bugs. vector
, on the other hand,
has had its bugs discovered & fixed ages ago.
If you must use dynamic memory, then consider unique_ptr
and shared_ptr
.
Double Delete
Every call to new
must be matched by exactly one delete
.
Not zero, and not two. One.
Similarly, every call to new
[]
must be matched
by exactly one delete
[]
.
Zero Delete
If you don’t call delete
, then the memory is forgotten.
We call this a memory leak.
Sure, the memory will be implicitly freed when the program ends.
However, some programs run for a good long time before they end.
This program allocates memory every second, and forgets to free it.
// Clock program
draw_clock_face();
while (sleep(1)) {
GraphicsContext *gc = new GraphicsContext;
gc->redraw();
// forget to free GraphicsContext
}
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Drip.
Multiple Delete
What happens if you call delete
more than once?
float *p = new float[100];
delete[] p;
delete[] p;
free(): double free detected in tcache 2
SIGABRT: Aborted
Pick Up Your Own Trash
- Sure, it would be possible to implement
new
& delete
so that they detect a double delete
, and respond with a sensible
error message.
- That would cost time, space, or probably both.
- Why should my clean code be slowed down to catch your errors?