Standard Library[lib]
C++ queue: how std::queue works, with examples
- Section
- Standard Library [lib]
- Standard
- C++11
- Compilers
- MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2, Clang 23.1 (libc++)
- Published
- Length
- 3 min read
Abstract
A C++ queue is std::queue, from the header <queue>: elements come back in the order they went in, first in, first out. push() adds at the back, front() reads the oldest element and pop() removes it and returns nothing, so read front() first. Calling front(), back() or pop() on an empty queue is undefined behavior, so check empty() before them. A queue has no iterators: loop until empty() is true, reading front() and popping.

A C++ queue is a std::queue, from the header <queue>, which hands elements back in the order they went in: first in, first out. push() adds an element at the back, front() reads the oldest one and pop() removes it. pop() returns nothing, so read front() first, and check empty() before either.
A print queue with three jobs:
#include <iostream>
#include <queue>
#include <string>
int main() {
std::queue<std::string> jobs;
jobs.push("report.pdf");
jobs.push("photo.png");
jobs.push("invoice.pdf");
std::cout << jobs.front() << '\n'; // report.pdf, the oldest
jobs.pop(); // removes report.pdf
std::cout << jobs.front() << '\n'; // photo.png
std::cout << jobs.size() << '\n'; // 2
}— end example]
It printed:
report.pdf
photo.png
2— end example]
This answer is written for C++11, the standard that added emplace() (Since When’s C++11 table lists the rest of what it added). The samples were built as C++11 with GCC 16.2 and Clang 23.1 (libc++), and as C++17 with those two, MSVC 19.44 and Clang 19.1 (MSVC STL); MSVC has no C++11 mode. All four printed the same unless a sentence says otherwise.
How do you add to a queue and read from it?
push() adds an element at the back, and emplace() does the same but builds the element in place from its arguments. front() and back() read the two ends; size() counts the elements and empty() says whether there are none. The type in the angle brackets is what the queue holds, and a new queue starts empty:
std::queue<std::string> jobs;
std::cout << std::boolalpha;
std::cout << jobs.empty() << '\n'; // true
jobs.push("report.pdf"); // adds at the back
jobs.emplace("photo.png"); // builds the string there
jobs.push("invoice.pdf");
std::cout << jobs.front() << '\n'; // report.pdf, the oldest
std::cout << jobs.back() << '\n'; // invoice.pdf, the newest
jobs.front() = "report-v2.pdf"; // front() is a reference
std::cout << jobs.front() << '\n'; // report-v2.pdf
std::cout << jobs.size() << '\n'; // 3
std::cout << jobs.empty() << '\n'; // false— end example]
All four printed what the comments show. The members of std::queue:
| Member | What it does | Returns |
|---|---|---|
push(x) |
adds x at the back |
nothing |
emplace(args) |
builds an element at the back from args |
nothing (since C++17, a reference to the new element) |
front() |
reads the oldest element | a reference to it |
back() |
reads the newest element | a reference to it |
pop() |
removes the oldest element | nothing |
size() |
counts the elements | the number |
empty() |
checks for no elements | true or false |
Why does pop() return nothing?
pop() returns nothing: it removes the front element and its return type is void. The original STL’s documentation gives the reason: returning the element would take a copy, since a reference to it would dangle, and front() reads it without one. Code that expects the removed element from it does not compile:
std::string job = jobs.pop(); // error: pop() returns void— end example]
Clang said:
error: no viable conversion from 'void' to 'std::string'— end example]
MSVC reports the same line as error C2440, cannot convert from 'void'. To keep the element, copy it out first and pop second: std::, then jobs.pop();.
What happens if the queue is empty?
Calling front(), back() or pop() on an empty queue is undefined behavior: the standard places no requirement on what the program then does, and no exception is promised. A queue passes those calls to the container underneath, and that container’s front(), back() and pop_front() require that it is not empty ([sequence.reqmts]). Test empty() first:
void print_next(std::queue<std::string>& jobs) {
if (!jobs.empty()) {
std::cout << "printing " << jobs.front() << '\n';
jobs.pop();
} else {
std::cout << "nothing to print\n";
}
}— end example]
Called twice on a queue holding only report.pdf, it printed printing report.pdf, then nothing to print.
How do you loop through a queue?
Loop while the queue is not empty, reading front() and then popping, until nothing is left:
while (!jobs.empty()) {
std::string job = jobs.front(); // read the oldest first
jobs.pop(); // then remove it
std::cout << "printing " << job << '\n';
}
std::cout << jobs.size() << '\n'; // 0— end example]
With the three jobs in it, all four printed printing report.pdf, printing photo.png and printing invoice.pdf in that order, then 0.
A queue has no iterators, so a range-for over it does not compile. for (const auto& job : jobs) stopped with Clang’s invalid range expression of type 'std:: and no viable 'begin' function available; MSVC’s is error C3312, no callable 'begin' function found.
To print a queue and keep it, loop over a copy. A parameter taken by value is a copy:
void print_all(std::queue<std::string> jobs) { // takes a copy
while (!jobs.empty()) {
std::cout << jobs.front() << '\n';
jobs.pop(); // pops the copy
}
}— end example]
All four printed the three jobs, and the original queue still had a size() of 3 afterwards.
Queue vs stack: what is the difference?
A queue hands back the oldest element first, and a stack the newest: last in, first out. Side by side:
| Property | std::queue |
std::stack |
|---|---|---|
| Order | first in, first out | last in, first out |
| Adds | push(), at the back |
push(), on top |
| Reads | front(), the oldest |
top(), the newest |
| Removes | pop(), the oldest |
pop(), the newest |
pop() returns |
nothing | nothing |
| Header | <queue> |
<stack> |

The same three files as an undo history:
std::stack<std::string> history; // an undo history
history.push("report.pdf");
history.push("photo.png");
history.push("invoice.pdf");
std::cout << history.top() << '\n'; // invoice.pdf, the newest
while (!history.empty()) {
std::cout << "undo " << history.top() << '\n';
history.pop();
}— end example]
All four printed invoice.pdf, then undo invoice.pdf, undo photo.png and undo report.pdf: the reverse of the order they went in. A std::stack has no iterators either.
What are std::deque and std::priority_queue?
A std::deque (header <deque>) is a double-ended queue that you can also index and loop over, and a std::priority_queue hands back the largest element first instead of the oldest.
The deque is the container that a std::queue and a std::stack keep their elements in unless you name another; the two are container adaptors, which wrap a container and let you reach only some of it. Use a std::deque directly when you need both ends, an index or a loop. Adding or removing at either end takes constant time, and so does reading by index:
std::deque<std::string> jobs;
jobs.push_back("photo.png");
jobs.push_back("invoice.pdf");
jobs.push_front("report.pdf"); // jumps the line
std::cout << jobs[1] << '\n'; // photo.png
for (const auto& job : jobs) // a deque has iterators
std::cout << job << '\n';
jobs.pop_front(); // removes report.pdf
jobs.pop_back(); // removes invoice.pdf
std::cout << jobs.size() << ' ' << jobs.front() << '\n';— end example]
All four printed photo.png for jobs[1], then report.pdf, photo.png and invoice.pdf from the loop, and last 1 photo.png.
A priority queue, std::priority_queue, is also in <queue>. It hands back the smallest element first when std::greater is its third template argument, and top() reads the next one:
std::priority_queue<int> priorities;
priorities.push(3);
priorities.push(5);
priorities.push(1);
while (!priorities.empty()) {
std::cout << priorities.top() << '\n'; // 5, 3, 1
priorities.pop();
}
// ...
std::priority_queue<int, std::vector<int>, std::greater<int>>
lowest_first;— end example]
All four printed 5, 3 and 1 from the first, and 1, 3 and 5 from lowest_first after the same three pushes. For a type of your own, the comparison (std::less by default, or one you pass as the third argument) must be a strict weak ordering, a consistent “less than”: the same rule as a comparator for std::sort and std::map.
Which one should you use?
| You need | Use | Header |
|---|---|---|
| First in, first out | std::queue |
<queue> |
| Last in, first out | std::stack |
<stack> |
| Both ends, an index or a loop | std::deque |
<deque> |
| The largest or the smallest next | std::priority_queue |
<queue> |
| A list you index and grow at the end | std::vector |
<vector> |
A checklist for queue code:
- Include
<queue>and<string>for a queue of strings. - Read
front()beforepop():pop()returns nothing. - Check
empty()beforefront(),back()orpop(). - Loop with
while (!jobs.empty()); for a range-for, keep the jobs in astd::deque. - To clear a queue, assign it an empty one:
jobs = {};.
None of these containers has a lock of its own: two threads that share one need a std::mutex, held across empty(), front() and pop() together, not around each call alone. The rest of the containers and the library are in Standard library.
Questions
Is std::queue thread safe?
No. A std::queue has no lock of its own, so two threads that share one, either of them pushing or popping, need a std::mutex. Hold it across each whole step, empty(), front() and pop() together: a lock around each call alone still lets the other thread take the last element between empty() and front().
How do you clear a queue in C++?
A std::queue has no clear() member. Assign it an empty queue instead: jobs = {}; or jobs = std::; empties it, and both did on all four compilers.
What is the time complexity of push and pop on a queue?
On a std::queue and a std::stack, push() and pop() take amortized constant time: constant on average over many calls, whatever the size. On a std::priority_queue, push() and pop() are logarithmic in the number of elements, and top() is constant.
What container does std::queue use?
A std::deque by default, and std::stack uses one too. A second template argument picks another, such as std::queue<int, std::list<int>>: the container must provide front(), back(), push_back() and pop_front(), which std::deque and std::list do. std::priority_queue uses a std::vector by default.
Can you access the middle of a queue?
No. A std::queue gives access to its two ends only, through front() and back(), and has no index and no iterators. If you need an element in the middle, use a std::deque, which has both ends, an index and iterators.
Which header do you include for a queue?
Include <queue> for std::queue, and for std::priority_queue, which is declared in the same header. std::stack is in <stack> and std::deque in <deque>.
Sources
- std::queuecppreference.com
- queue (the original STL documentation, note 3)SGI Standard Template Library documentation, hosted by Boost
- std::queue::popcppreference.com
- [sequence.reqmts] RequirementsC++ standard working draft
- std::stackcppreference.com
- std::dequecppreference.com
- std::priority_queuecppreference.com