UPI Study › Courses › C++ Programming › Free lessons › Lesson 10.7 Free with a free account
Dynamic Allocation
C++ Programming · Chapter 10: File Access and MemorySection 10.7 · lesson 75 of 84video coming soon
← The Memory LandscapeNext lesson: Detecting and Eliminating Memory Leaks →
In this lesson
Borrowing and returning memory at run time.
- Contrast block-tied memory with memory you control
- Allocate and release values, arrays and objects
- Grow an array; build and release a 2-D grid
- Say why vector and unique_ptr are the everyday choice
Transcript
Everything said in the video, section by section (1,542 words). Read along, or search it.
Opening Problem
Fixed Sizes Are a Real Limit
Every array so far has needed its size settled before the program was built. That's a real limit. A program can't ask how many readings there are, and then make room for exactly that many. Dynamic allocation removes the limit, by letting a program request memory while it runs. In exchange, it hands you the responsibility for giving that memory back.
Lifetime
Dynamic Memory Outlives Its Block
An ordinary local variable exists because the block it was declared in is running. When the block ends, it's gone. Automatically, unavoidably, at a moment decided by the shape of the code. Dynamic memory works the opposite way. You ask for space while the program runs, and you receive its address. That space stays yours until you say otherwise. The block ending doesn't release it. Nothing releases it. Notice that the pointer itself is an ordinary local. It disappears with its block, but what it points at does not. In this run, make has ended, yet the forty-two is still there to print. That's the arrangement's whole power, and the reason releasing memory has to be deliberate.
Syntax
Asking For and Returning One Value
New, followed by a type, asks for room for one value. Here, an int holding forty-two. New produces an address, which is why the variable receiving it is a pointer. You reach the value through the pointer, with the star. Delete gives the memory back. But it doesn't change the pointer, which still holds the old address, now meaningless. Setting it to nullptr immediately afterward costs nothing, and makes the pointer's state honest.
Comparison
Automatic Versus Dynamic Integers
Here's the same value, held two ways. An automatic int comes into being when its declaration is reached. A dynamic one, when new runs. The automatic one goes away when the block ends, and you have no say. The dynamic one goes away when you write delete, and otherwise, never. One is reached by name, the other through the pointer. Only the dynamic form can have its size decided while running. That's the main reason to use it. And if you forget about it, the automatic one is cleaned up regardless. The dynamic one stays taken for as long as the program runs.
Worked Example
Sizing an Array at Run Time
This is the case that motivates the whole topic. The number of readings isn't known when the program is written, so no ordinary array can be declared for it. But new, with square brackets, accepts a count worked out at run time. Here, the program asks how many readings there are, then allocates exactly that many doubles. Subscripts work exactly as before. With four readings, the sum is nine. And the release is delete with square brackets. Note those brackets, because they matter.
Key Rules
Two Pairings and Single Release
There are exactly two pairings, and they're absolute. Memory from new is released by delete. Memory from new with brackets is released by delete with brackets. Crossing them is a fault the compiler can't catch, and the program won't report. The compiler can't help, because a pointer to one value and a pointer to an array look identical. Only you know which form produced it. The second rule is that every allocation is released exactly once. Not zero times, and not twice.
Compiler Warning
Clang Flags Crossed Pairings
Some compilers do notice an obvious crossing, like this one, and warn. They can only see it when the allocation is right in view. Do not rely on that. Here clang flags both crossings. Still, this program is wrong, so it is compiled, never run.
Objects
Constructors and Destructors with New
Allocating an object does more than reserve space. New reserves the space, and then runs the constructor. Delete runs the destructor, and then releases the space. The object gets the same treatment it would as a local variable. Only the timing of the second half differs. So forgetting delete on an object doesn't only waste memory. It means the destructor never runs at all. In the output, tape is built, but never destroyed. Anything the object was going to do on the way out, like closing a file, or writing a final line to a log, simply doesn't happen.
Concept
Growing Means Three Operations
Dynamic memory doesn't stretch. An allocation of forty is forty, for as long as it exists. So making it bigger is really three operations. First, allocate a larger block. Here, room for eight, while the old block holds four values. Second, copy every value across. Third, release the old block, and point the name at the new one. The order matters. Release the old block first, and the copy has nothing to read from.
Code Walkthrough
Growing the Readings Array
Here's that sequence in code. Allocate the bigger block, copy each value out of the old one, then delete the old block. Finally, the name readings is pointed at the larger block. Release first and the copy would read memory that is already gone. Run it: the first reading survived, and the new fifth place holds five.
Cost Analysis
Why Containers Grow by Doubling
Every growth copies everything. Growing by one place each time makes a thousand additions cost roughly half a million copies. That's why real containers grow by doubling. This loop counts both strategies. By one, four hundred ninety-nine thousand five hundred copies. By doubling, one thousand twenty-three. The copying still happens, but rarely enough that the average cost of adding one item stays small.
Concept
Two Dimensions from Row Pointers
A dynamic two-dimensional arrangement is built from one-dimensional pieces. It's an array of pointers, and each pointer refers to a row. Every row is allocated on its own, so the rows aren't necessarily next to each other in memory. Nothing requires them to be. Grid, index one, index two, still works exactly as it would on a fixed two-dimensional array.
Code Walkthrough
Building and Freeing the Grid
Building it takes a loop. First, allocate the array of row pointers. Then allocate each row, separately. Taking it apart takes the same loop in reverse. Release every row first, then the array of pointers. Reverse that order, and the row addresses are gone before you can use them. The rows would be lost for the rest of the run.
Failure Handling
When an Allocation Request Fails
A request for memory can fail, for an implausible size, or on a machine with little left. By default, new reports this by throwing an exception, standard bad alloc, rather than returning an unusable pointer. So a program that ignores the possibility stops, rather than continuing with nonsense. Where you'd rather test for it, ask for the no-throw form. It yields nullptr instead, and you can check and report.
Modern Practice
Why Manual Allocation Is Rarely Used
Everything so far is worth understanding, and it's not the way to write new programs. The operations aren't difficult individually. The problem is that the obligation is unbounded. Every path out of every function that allocated something must release it, including the paths you didn't think about. A vector is sized at run time, grows itself by doubling, and releases automatically on every path out. And make unique gives you one owned object. You use it like a pointer, and its destructor runs without being asked.
Side by Side
By Hand Versus Standard Tools
Here are the same jobs, done by hand and done for you. An array sized at run time needs a delete on every path out, by hand. A vector is released however the block ends. Growing by hand means allocate, copy, release and repoint, written correctly each time. Push back does the same steps, already correct. One owned object, by hand, is new plus a delete that must be reached. With make unique, it's owned for you. By hand, the size is a separate variable you must keep in step. A vector's size can't disagree with its contents. And if something goes wrong halfway, the hand-written release is skipped. The standard tools still release, because release is tied to the block ending.
Motivation
Reasons to Learn the Manual Form
So why learn the manual form at all? Three reasons. It's what vector and unique pointer are doing underneath, and knowing that turns them from magic into machinery. A great deal of existing code is written this way, and has to be read. And its failures are the subject of the next section: memory never returned, memory returned twice, and pointers left referring to released space. Those failures only make sense once you know what was supposed to happen.
Vocabulary
Free Store and Ownership Terms
The free store is where memory is taken from at run time, and returned to when released. Allocation, with new, yields an address. Release, with delete, gives it back, matched to the form used. Lifetime is the span from creation to destruction. For dynamic memory, you choose both ends. Capacity is how many elements an allocation has room for, fixed for that allocation. Reallocation grows it by allocating, copying and releasing. And an owning pointer is responsible for releasing what it points at. Unique pointer makes that responsibility automatic.
Quick Check
Returning Without Releasing an Array
Quick check. A function allocates an array and returns without releasing it. What happens to the pointer, and what happens to the memory? Pause and think. The pointer is an ordinary local, so it vanishes with the function. The memory does not. It stays taken, and now nothing can reach it to release it.
Key Takeaways
Dynamic Memory Rules in Review
To summarize. Dynamic memory outlives its block, and nothing releases it for you. New pairs with delete, and the bracket forms pair with each other, with each allocation released exactly once. Delete runs the destructor. Forget it, and the destructor never runs. Grow by allocating, copying, then releasing. And free the rows before the array that holds them. In new code, use vector and unique pointer.
About C++ Programming at UPI Study
C++ Programming (Computer Science 242) is a self-paced online course of 84 video lessons in 11 chapters, from your first program to decisions, loops, arrays, functions, classes, files, pointers and inheritance. It carries a NCCRS credit recommendation for 3 semester credits.
Every lesson transcript is free on pages like this one, and the videos are free with a free UPI Study account. Enrolling adds a practice quiz after each lesson, the graded work and final exam that earn the credit, lifetime access, and an official transcript on completion. UPI Study has helped over 130,000 students with college credits. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Enroll now → Course details Download the syllabus Every course with PRO →
Why take it here
Why students take C++ Programming with UPI Study
Where the credit goes
Universities that work with NCCRS
C++ Programming carries a NCCRS credit recommendation. These universities work with NCCRS; some are UPI Study's signed partners. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Thomas Edison State UniversitySigned partner
University of the PeopleSigned partner
Charter Oak State CollegeSigned partner
Strayer UniversitySigned partner
Columbia Southern UniversitySigned partner
Indiana TechSigned partner
Penn StateWorks with NCCRS
Southern New Hampshire UniversityWorks with NCCRS
SUNYWorks with NCCRS
+many more cooperating universitiesFind my college →Find my college → Not listed? Ask Athena in the corner of this page, or book a 15-minute call.
FAQ
Questions students ask us
About Dynamic Allocation
What is the difference between automatic memory and dynamic memory in C++?
How do I allocate an array with new and free it correctly in C++?
How do you make a dynamic array bigger in C++?
Why should I use vector and unique_ptr instead of new and delete?
About the C++ Programming course
How many college credits is C++ Programming?
How much does C++ Programming cost and what is included?
Which universities accept UPI Study credits?
How long does C++ Programming take?
How are the exams done?
How do my credits reach my college?
Ready for the full course? Earn 3 credits in C++ Programming.
84 video lessons, a quiz after each one, and the graded work that earns the credit. Recommended for credit by NCCRS.
3 credits · NCCRSEnroll →