Standard Library[lib]

Stack in C++: how std::stack works, with examples

Section
Standard Library [lib]
Standard
C++17
Compilers
MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2, Clang 23.1 (libc++)
Published
Length
6 min read
In this answer8 clauses
  1. 1How do push, top and pop work?
  2. 2What happens if you pop or top an empty stack?
  3. 3How do you loop through a stack?
  4. 4What is a stack used for?
  5. 4.1Reverse a word
  6. 4.2Check that brackets are balanced
  7. 5How is a stack implemented in the STL?
  8. 6Stack vs queue: what is the difference?
  9. 7Is std::stack the same as “the stack” in memory?
  10. 8A checklist for stack code

Abstract

A stack in C++ is std::stack, from the header <stack>: the last element pushed is the first one back, last in, first out. push() adds on top, top() reads the top element and pop() removes it and returns nothing, so read top() first. Calling top() or pop() on an empty stack is undefined behavior, so check empty() before either. A stack has no iterators: loop while it is not empty, reading top() and popping.

Three equal hatched slabs lie in a well open only at the top. A fourth, blue slab is lifted just above them; an arrow comes down onto it from the left and another rises from it to the right.
Figure 1 — Last in, first out: a stack takes elements in and gives them back at the top only.

A stack in C++ is a std::stack, from the header <stack>: a container that hands back the most recently added element first, last in, first out. push() adds an element on top, top() reads the top element and pop() removes it. pop() returns nothing, so read top() first, and check empty() before either.

A browser’s back button, in a whole program:

[Example 1:
#include <iostream>
#include <stack>
#include <string>

int main() {
    std::stack<std::string> history;
    history.push("home");
    history.push("search");
    history.push("article");

    std::cout << history.top() << '\n';    // article
    history.pop();                         // removes "article"
    std::cout << history.top() << '\n';    // search
    std::cout << history.size() << '\n';   // 2
}

— end example]

It printed:

[Example 2:
article
search
2

— end example]

The last page pushed, article, is the first one top() reads and the first one pop() removes. The answer is written for C++17 (Since When’s C++17 table gives the first GCC, Clang and MSVC releases of its features). The samples were built as C++17 with MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2 and Clang 23.1 (libc++), and all four printed the same.

How do push, top and pop work?

All three act on the top only: push() puts a new element there, top() gives you that element to read or change, and pop() takes it off. emplace(), in the library since C++11, also adds on top, but builds the element in place from its arguments:

[Example 3:
std::stack<std::string> history;
std::cout << std::boolalpha;
std::cout << history.empty() << '\n';  // true

history.push("home");                  // copies or moves it in
history.push("search");
history.emplace("article");            // builds it in place

std::cout << history.top() << '\n';    // article
history.top() = "settings";            // top() is a reference
std::cout << history.top() << '\n';    // settings

std::cout << history.size() << '\n';   // 3
std::cout << history.empty() << '\n';  // false

— end example]

All four printed true, article, settings, 3 and false. top() returns a reference to the top element, so assigning through it changed article to settings.

Three piles, left to right. First: article on search on home, top() pointing at article, and a two-headed arrow at its top. Second: article greyed out, pop() lifting it off. Third: search on home, top() at search.
Figure 2 — Only the top of a stack can be read or removed: the newest element leaves first.

The members of std::stack:

Member What it does Returns
push(x) adds x on top nothing
emplace(args) builds an element on top from args nothing before C++17; since C++17, a reference to the new element
top() reads the top element a reference to it
pop() removes the top element nothing
size() counts the elements the number
empty() checks for no elements true or false

Because pop() returns void, code that expects the removed element from it does not compile:

[Example 4:
std::string page = history.pop();   // error: pop() returns void

— end example]

Clang said:

[Example 5:
error: no viable conversion from 'void' to 'std::string'

— end example]

MSVC reports the same line as error C2440. To keep the element, copy it first and pop second: std::string page = history.top();, then history.pop();.

What happens if you pop or top an empty stack?

Calling top() or pop() on an empty stack is undefined behavior: the standard sets no rule for what happens next and promises neither an exception nor a crash, unless, since C++26, a hardened standard library checks the call first and reports a contract violation. A stack passes both calls to its container’s back() and pop_back(), and those require a container that is not empty ([sequence.reqmts]). Test empty() first:

[Example 6:
void go_back(std::stack<std::string>& history) {
    if (history.empty()) {              // check before top() and pop()
        std::cout << "nothing to go back to\n";
        return;
    }
    std::cout << "back from " << history.top() << '\n';
    history.pop();
}

— end example]

Called twice on a stack holding only article, it printed back from article, then nothing to go back to.

How do you loop through a stack?

Loop while the stack is not empty, reading top() and then popping; the elements come out newest first:

[Example 7:
while (!history.empty()) {
    std::cout << history.top() << '\n';
    history.pop();
}
std::cout << history.size() << '\n';   // 0: the loop emptied it

— end example]

With home, search and article pushed in that order, all four printed article, search and home, then 0.

A stack has no iterators, the objects a range-for uses to walk through a container, so for (const auto& page : history) does not compile. Clang stops with invalid range expression of type 'std::stack<std::string>' and no viable 'begin' function available.

What is a stack used for?

A stack fits any job where the last thing in is the first thing you need back: a back button, an undo list, the brackets still open in a line of code. Two of them are common course exercises.

Reverse a word

Push each letter, then pop them all; the last letter comes out first:

[Example 8:
std::string reversed(const std::string& word) {
    std::stack<char> letters;
    for (char letter : word)
        letters.push(letter);           // first letter at the bottom

    std::string result;
    while (!letters.empty()) {
        result += letters.top();        // last letter comes out first
        letters.pop();
    }
    return result;
}

— end example]

It printed kcats for “stack” and elcitra for “article”.

Check that brackets are balanced

Push each opening bracket; each closing bracket must match the one on top, which is the most recent bracket still open:

[Example 9:
char opener_for(char closer) {
    if (closer == ')') return '(';
    if (closer == ']') return '[';
    return '{';
}

bool balanced(const std::string& text) {
    std::stack<char> open;
    for (char c : text) {
        if (c == '(' || c == '[' || c == '{') {
            open.push(c);
        } else if (c == ')' || c == ']' || c == '}') {
            if (open.empty())
                return false;           // a closer with nothing open
            if (open.top() != opener_for(c))
                return false;           // it closes the wrong bracket
            open.pop();
        }
    }
    return open.empty();                // anything left was never closed
}

— end example]

All four printed true for {[()]}, false for ([)], whose ) meets a [ on top, and false for ((, which leaves two brackets open.

How is a stack implemented in the STL?

On top of another container: a std::deque, a double-ended queue, unless you name another. std::stack is a container adaptor, a class that wraps a container and lets you reach only its top: its push(), top() and pop() call the container’s push_back(), back() and pop_back() ([stack.defn]). Any sequence container with those three can sit underneath, and std::vector, std::deque and std::list all qualify. A second template argument picks one, here a std::vector:

[Example 10:
std::stack<int, std::vector<int>> numbers;   // a vector underneath
numbers.push(10);
numbers.push(20);
numbers.push(30);

std::cout << numbers.top() << '\n';    // 30
numbers.pop();
std::cout << numbers.top() << '\n';    // 20
std::cout << numbers.size() << '\n';   // 2

— end example]

All four printed 30, 20 and 2. Courses also ask for a stack written by hand on an array or a linked list; in real code, std::stack is the one to use. The other containers are in Standard library.

Stack vs queue: what is the difference?

A stack hands back the newest element first, last in, first out; a queue hands back the oldest, first in, first out:

Property std::stack std::queue
Order last in, first out first in, first out
Adds push(), on top push(), at the back
Reads top(), the newest front(), the oldest
Removes pop(), the newest pop(), the oldest
Header <stack> <queue>

The queue’s members and examples are in C++ queue: how std::queue works.

Is std::stack the same as “the stack” in memory?

No. “The stack”, as opposed to “the heap”, is the region of memory where a function’s local variables live, and std::stack is a container you create. They share the last-in, first-out idea and nothing else: with the default allocator, the std::deque under a std::stack allocates its elements on the heap.

A checklist for stack code

  • Include <stack>, and <string> for a stack of strings.
  • Read top() before pop(): pop() returns nothing.
  • Check empty() before top() or pop().
  • Loop with while (!history.empty()); a range-for does not compile.
  • To look below the top, keep the elements in a std::vector or a std::deque instead.

Questions

Is std::stack thread safe?

No. A std::stack has no lock of its own: threads may read one at the same time, but once any thread pushes or pops, every access needs a std::mutex, held across empty(), top() and pop() together. A lock around each call alone still lets another thread pop the last element between one thread checking empty() and reading top().

How do you clear a stack in C++?

A std::stack has no clear() member. Assign it an empty stack instead: history = {}; or history = std::stack<std::string>(); emptied it on all four compilers, leaving a size() of 0.

What is the time complexity of push and pop on a stack?

top() takes constant time, O(1). push() and pop() take what the container underneath takes for push_back() and pop_back(), and on the default std::deque that is O(1) too, however many elements the stack holds.

How do you print a stack without emptying it?

Pass the stack to the printing function by value, so the function gets a copy of its own, and pop that copy in a while loop. The caller keeps every element. The copy duplicates them all, so for elements you read often without removing, a std::vector, which you can loop over directly, suits better.

How do you initialize a stack with values in C++?

Put the values in a container of the stack's own type and pass it to the constructor: with values a std::deque<int> holding 10, 20 and 30, std::stack<int> numbers(values); has 30 on top. A stack has no constructor that takes a list, so std::stack<int> numbers = {10, 20, 30}; does not compile.

What is the difference between a stack and a vector?

A std::vector lets you read any element by its index and loop over all of them; a std::stack lets you reach only the top. A vector used only through push_back(), back() and pop_back() works as a stack, and std::stack<int, std::vector<int>> is exactly that, under the stack's names.

Sources

  1. std::stackcppreference.com
  2. std::stack::popcppreference.com
  3. std::stack::topcppreference.com
  4. std::stack::emplacecppreference.com
  5. [sequence.reqmts] RequirementsC++ standard working draft
  6. [stack.defn] DefinitionC++ standard working draft

Read next

  1. C++ queue: how std::queue works, with examplesStandard Library · Miriam Castellanos · written for C++11
  2. C++ linked list: write one, then use std::listStandard Library · Miriam Castellanos · written for C++17
  3. C++ random number: how to generate one in a rangeStandard Library · Miriam Castellanos · written for C++11