This module explains how to construct a dynamically sized stack by designing a C++ class that owns memory safely. You’ll start with a simple stack of characters and evolve it into a robust, modern implementation.
By the end of the module, you will understand:
The core theme is ownership: when your class allocates memory dynamically, it must also define how that memory is copied, moved, and cleaned up. That’s exactly what constructors, copy constructors, and destructors are about.
In C++, the word stack is used in two different ways:
This module is about the stack ADT. However, understanding the call stack and the heap is essential because a dynamically sized stack class typically stores its elements in dynamically allocated memory.
An automatic variable is created when its definition is executed and is typically stored in the program’s call stack. The call stack has a fixed size (configurable on many platforms), and memory for automatic variables is released automatically when the scope ends.
The heap (also called the free store) is a larger pool of memory used for objects whose lifetime must extend beyond a single scope.
You can request heap memory at runtime. Historically, this was done with new and released with delete.
A “dynamically sized” stack ADT typically means: the stack’s internal storage capacity can be chosen at runtime (or can grow as needed). Either approach involves heap-based storage, so memory ownership must be designed carefully.
If you allocate memory manually, you must also release it manually. Forgetting to release memory causes a leak; releasing it twice causes undefined behavior. One common safety pattern is to reset a pointer after releasing what it points to:
delete pvalue; // release memory pointed to by pvalue
pvalue = nullptr; // reset the pointer
Resetting the pointer helps prevent accidental use of a dangling address. However, modern C++ best practice is to avoid “naked” owning pointers entirely. Instead, prefer RAII-managed types such as:
std::vector<T> for dynamic arraysstd::string for text buffersstd::unique_ptr<T[]> when you truly need an owning dynamic array with pointer semantics
In this module, you’ll see the classic new[]/delete[] approach because it makes copy constructors and destructors “visible”.
But you’ll also see the modern RAII approach, because that’s what you should use in current C++ code.
A stack is a LIFO data structure. Unlike a list, you do not insert or remove elements at arbitrary positions. You interact with the top of the stack:
Stacks are widely used: function calls (call stack), expression evaluation, undo/redo features, parsing, and matching parentheses are all classic examples. In this module, we’ll focus on implementing the stack ADT as a C++ class with runtime-controlled storage.
The implementation path is intentionally incremental:
After that foundation is in place, you can safely build stack functionality (push/pop) and apply the structure to real tasks.