CS253: Software Development with C++

Spring 2021

Dynamic Memory

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

Scalar Example

int *p = new int;
*p = 42;
cout << p << ' ' << *p << '\n';
delete p;
0x1ab12b0 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,

new delete, new[] delete[]

Not initialized

auto *a = new short,
     *b = new short(42),   // or short{42}
     *c = new short[10],
     *d = new short[2]{11,22};
cout << a << " contains ⁇⁇.\n"
     << b << " contains " << *b << ".\n"
     << c << " contains ⁇⁇.\n"
     << d << " contains " << d[0] << ' ' << d[1] << '\n';
0x88c2b0 contains ⁇⁇.
0x88c2d0 contains 42.
0x88c2f0 contains ⁇⁇.
0x88c310 contains 11 22

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, had its bugs discovered & fixed long 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? That’s undefined behavior. Let’s see what it does on this computer:

float *p = new float[100];
delete[] p;
delete[] p;
free(): double free detected in tcache 2
SIGABRT: Aborted

Pick Up Your Own Trash

Dangling Pointers

double *laurel = new double(12.34);
cout << *laurel << '\n';            // should be 12.34
delete laurel;
cout << *laurel << '\n';            // value is unknown

double *hardy = new double(56.78);  // will probably re-use space
cout << *laurel << '\n';            // most likely 56.78 for laurel
delete hardy;
12.34
3.77861e-320
56.78

Magical Thinking

Another way to produce a dangling pointer

Don’t return a pointer to something that will soon go away.

// Return a cheery message:
const char *message() {
    char buf[] = "Hello there, folks!\n";
    const char *p = buf;
    return p;
}

int main() {
    cout << "I say: " << message();  // Why doesn’t this work!?
    return 0;
}

No Reference Counting

string *smith = new string("Brush your teeth after every meal!");
string *jones = smith;  // a shallow copy
delete smith;
cout << *jones << '\n';

A shortcut that will bite you

Note that an array size with a non-constant size is not allowed in C++, though some compilers with some settings (g++ without -Wpedantic) allow it as a non-portable extension.

int n = 42;
int data[n];
return data[0];
c.cc:2: warning: ISO C++ forbids variable length array 'data'