← C++, End to End

C++, End to End

Dynamic Memory Allocation

new and delete are C++'s direct interface to dynamic memory: allocate an object on the heap, and free it when you're done. They're the mechanism underneath every container and smart pointer in the standard library. You should understand them thoroughly and use them directly as rarely as possible.

new and delete

c++ · live, editable, runnableOpen in Compiler Explorer ↗

Using plain delete on something allocated with new[], or delete[] on something allocated with plain new, is undefined behavior. The two must always be paired correctly. This mismatch is exactly the kind of easy-to-miss bug that's a strong argument for not writing manual new/delete in the first place.

Why manual new/delete is a last resort now

Every object you allocate with new has to be freed with exactly one matching delete, on every code path, including ones that exit early, throw an exception, or return in the middle of a function. Miss one, and you leak memory. Free the same pointer twice, or use it after freeing it, and you get undefined behavior that might not show up until much later, in a completely unrelated part of the program.

c++ · live, editable, runnableOpen in Compiler Explorer ↗

std::vector, std::string, and smart pointers (covered in this course's dedicated move-semantics chapter) all solve exactly this problem using RAII: the object's constructor acquires the resource, and its destructor releases it, and destructors run automatically during stack unwinding, including when an exception is thrown. Wrap the raw resource in one of these, and the leak above becomes structurally impossible instead of something you have to remember to avoid.

c++ · live, editable, runnableOpen in Compiler Explorer ↗

Memory leaks and double frees, concretely

c++ · live, editable, runnableOpen in Compiler Explorer ↗
c++ · live, editable, runnableOpen in Compiler Explorer ↗

Both of these compile without warning or error in general, and neither necessarily crashes immediately. That delay between the mistake and its visible effect is exactly why these bugs are so much harder to track down than a syntax error, and exactly why the RAII-based alternative isn't just "nicer", it removes the entire bug category.

Placement new

Placement new constructs an object at a specific, already-allocated memory address, instead of allocating new memory itself: new (address) Type(args). It's a genuinely advanced, rare tool, used mostly by people implementing their own memory allocators, object pools, or low-level containers (in fact, this is exactly how std::vector itself constructs elements into its pre-allocated storage internally). You're very unlikely to need it in application code; it's mentioned here so the name doesn't come as a surprise if you encounter it, not as something to reach for.

Try it yourself: find and fix the leak

This function leaks memory on one specific path. Find it, then fix it, first with a manual delete, and then again the better way (removing manual memory management from this function entirely).

c++
int* findAndDouble(int* arr, int len, int target) {
    int* result = new int(0);
    for (int i = 0; i < len; ++i) {
        if (arr[i] == target) {
            *result = arr[i] * 2;
            return result; // fine, caller is responsible for this one
        }
    }
    return nullptr; // BUG: "result" was already allocated and is now leaked
}
c++ · live, editable, runnableOpen in Compiler Explorer ↗