When you work with key and value, knowing “How to Iterate Maps in C++” becomes an essential skill. The map container allows you to store data in sorted key order, but understanding how to properly access and traverse its elements can be confusing for beginners.
The short answer: the simplest way to iterate over a map in C++ is a range-based for loop. Each step of the loop gives you one key and one value.
for (const auto& [key, value] : myMap)
std::cout << key << " : " << value << std::endl;
That line needs C++17. If your compiler is older, write for (const auto& p : myMap) and use p.first and p.second instead.
In this article, you will learn what a C++ map is and explore different ways to iterate through it using practical examples. We will break down each method step by step so you can clearly understand each one. Every program on this page was compiled and run with g++ before we published it, and the output under each one is copied from that run.
By the end, you will feel confident writing clean and efficient map iteration code in C++.
TL;DR: Iterate Maps In C++
| Aspect | Summary |
|---|---|
| What is a C++ Map? | A std::map is an associative container that stores data as unique key-value pairs. Keys are automatically stored in sorted or ascending order. |
| How Map Iteration Works | Iteration moves from one key-value pair to the next, not by index. You access elements using iterators or range-based loops. |
| Methods to Iterate | You can use STL iterators, range-based for loops, structured bindings, std::for_each() with a lambda, and reverse iterators. Each method serves a different use case. |
| Map vs Unordered Map | std::map keeps elements sorted using a balanced tree, while unordered_map stores elements using hashing and does not guarantee order. |
| Changing Or Removing Elements | Use auto& to change values inside the loop. To remove elements inside the loop, use the iterator that erase() returns. |
| Best Practices | Map traversal takes O(n) time, while insertion and lookup take O(log n). Use auto, references (auto&), and const correctness for clean and efficient code. |
- What Are Maps In C++?
- Why Is Iterating Through Maps Difficult For Students?
- What Happens During Map Iteration?
- Basic Map Iteration Using STL Iterator
- Range-Based For Loops (with structured bindings and unordered_map)
- std::for_each And A Lambda Function
- Reverse Iteration
- Changing Values While Iterating
- Removing Elements While Iterating
- Only The Keys Or Only The Values
- Nested Maps, Maps Of Vectors, And Multimaps
- Iterating Over Part Of A Map
- Comparison Table Of All Methods
- How To Choose The Right Method
- Common Mistakes
- Frequently Asked Questions
What Are Maps In C++? Read Below
You might have heard about dictionaries in Python; maps in C++ also work similarly. A C++ map is an associative container that is used to store elements in the form of key-value pairs.
In maps, each element is associated with a unique identifier. This unique identifier represents the 'key,' and the element represents the 'value' associated with the key in the pair.
Unlike other containers like arrays or vectors, where elements are stored sequentially, maps utilize key-value pairs.
Let's discuss the key value structure of maps in more detail before we jump into discussing how to iterate over maps in C++.
Understand Key-Value Pair Structure Of Maps
As we said above, keys are identifiers that have some values associated with them. In maps, we have unique keys, which means that no two elements can have the same identifier linked to them.
C++ maps store the key-value pairs in a balanced binary tree. A key acts like a label that we can use to retrieve the corresponding data value. Keep in mind that only the keys have to be unique. Two different keys can hold the same value. For example, two students can have the same score.
The pairs are kept in ascending order of their keys in the balanced binary tree, which makes it efficient for us to perform operations like insertion and deletion. Let's see how to create a map and insert the key-value pairs in it.
We will also use the same to understand the map iteration process. Have a look at the syntax given below.
std::map<key_datatype, value_datatype> map_name = {{key1, value1}, {key2, value2}};
// for example, student names with their ID numbers
std::map<std::string, int> Student = {{"Alex", 1}, {"Joe", 2}, {"Charlie", 3}};
To use it in your code, you need to use the <map> header file. Map container is a part of the STL or Standard Template Library in C++; thus, we have used std::map in this case.
The key_datatype and value_datatype can be anything, like string, int, float, etc. Once you have created the map, you can insert the elements into it. There are many operations you can perform on this data.
If you want to see how to create a map, add elements, and look them up before you get into iteration, check out our guide on the C++ dictionary (map). It will help you see maps in the bigger picture.
Why Is Iterating Through Maps In C++ Difficult For Students?
For the last decade, I have been mentoring students in C++, and I have noticed that many students quickly understand the map concept, but struggle when it comes to traversing it.
From my experience, I have decoded the reasons behind it. Some major reasons are the following.
1) Students Don’t Understand What A Map Actually Stores:
Many students think a map behaves like an array or vector. But, they forget that a C++ map stores key and value pairs, not single values, like the following code. This makes the iteration look unfamiliar.
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
map<int,string> m{{1,"A"},{2,"B"}}; // The Map Declaration
for(auto it = m.begin(); it != m.end(); ++it)
cout << it->first << " " << it->second << endl; // Key And Value
}
Output:
1 A 2 B
Students often try to print ‘it’ directly, expecting one value. The confusion happens because each element is a pair, not a single number. If you write cout << it, the compiler stops with an error that starts like this:
main.cpp:9:14: error: no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'std::_Rb_tree_iterator<std::pair<const int, std::__cxx11::basic_string<char> > >')
The full message is much longer, and it scares a lot of beginners. All it is saying is, "I do not know how to print an iterator." Print it->first and it->second instead.
2) Iterator Syntax Feels Complicated:
I have noticed that the use of ‘it->first’ and ‘it->second’ looks intimidating to beginners. They struggle to understand why the dot (.) cannot be used directly, as they are used to the dot (.) operator.
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
map<int,string> m{{1,"A"},{2,"B"}};
for(auto it = m.begin(); it != m.end(); ++it)
{
cout << it->first << " "; // Accessing The Key
cout << it->second << " | "; // Accessing The Value
cout << (*it).first << " "; // Same Key, Written With The Dot
cout << (*it).second << endl; // Same Value, Written With The Dot
}
}
Output:
1 A | 1 A 2 B | 2 B
Here, the ‘it’ is an iterator, which is a pointer-like object. It is not the pair itself. Students get confused because they don’t connect iterators with pointer behavior.
As the output shows, it->first and (*it).first give the same result. The arrow is just a shorter way to say "go to the pair this iterator points at, then take first."
3) Order Of Output Is Not What They Expect:
Students sometimes expect the map to print values in the order they inserted them. But ‘std::map’ automatically sorts elements by key. Students can’t connect this, which confuses them more in the lab exam.
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
map<int,string> m;
// Insertion of the unsorted data
m[3] = "C";
m[1] = "A";
m[2] = "B";
for(auto p : m)
cout << p.first << " "; // Data Will Be Printed In Sorted Order
cout << endl;
}
Output:
1 2 3
Even though the insertion order was 3, 1, 2, the output is sorted. Students do not expect this automatic sorting. Hence, they predict the wrong output in the lab or on a quiz and lose points.
Deep Thinking: What Happens During Map Iteration?
The central reason behind such confusion is that students don’t clearly understand the iteration process. From my expertise, I have designed a student mental model that has already helped a lot of students.
Keep in mind that a map is not an indexed list; it is a collection of key and value pairs stored in sorted order, specifically for ‘std::map’. Here is a simple way to picture it:
- Think of a map as a shelf of labeled boxes where each box has a label, which is the Key.
- Inside each box, there is a value. The boxes are arranged in alphabetical or numerical order by label.
Now, imagine walking along that shelf where each step of iteration will be the following.
- Move to the next box, and you will get access to the 'first' and 'second.'
- The ‘first’ is the label or key, and the 'second' is what is inside the box or value.
So, you are not moving by index like i = 0, 1, 2. You are moving from one key-value pair to the next. Once students understand this mental picture, iteration becomes much easier to follow.
How To Do Basic Map Iteration Using STL Iterator?
The Standard Template Library allows us to create an iterator object for maps. We can initialize the iterator to start from the beginning of the map and traverse it till the end. Look at the example code below to understand how it works.
#include <iostream>
#include <map>
#include <string>
int main()
{
std::cout <<"-----MAP ITERATION--------"<<std::endl;
// create a map named Student and insert the elements in it
std::map<std::string, int> Student = {{"Alex", 1}, {"Joe", 2}, {"Charlie",3}};
// initialize the position of the iterator to the start of the map
std::map<std::string, int>::iterator it = Student.begin();
// iterate till the end of the map
while (it != Student.end())
{
// get key
std::string name = it->first;
// get value
int id = it->second;
std::cout << name << " : " << id << std::endl;
// iterator incremented to point next item
it++;
}
return 0;
}
Explanation Of The Program:
- We have created a map named Student that has the names of some students and their ID numbers.
- We are then creating and initializing an iterator called 'it', pointing at the beginning, that will help us traverse the map till the end.
- For every iteration, we are accessing the key and value using the 'it' iterator till the end of the map.
Let's check out the output to see if we have traveled through all elements or not.
Output:
-----MAP ITERATION-------- Alex : 1 Charlie : 3 Joe : 2
Notice that Charlie comes before Joe, even though we inserted Joe first. The keys are strings, so the map keeps them in alphabetical order.
The type std::map<std::string, int>::iterator is long to write. In everyday code, it is common to let auto work out the type and put everything in a for loop. This shorter program does the same job:
#include <iostream>
#include <map>
#include <string>
int main()
{
std::map<std::string, int> Student = {{"Alex", 1}, {"Joe", 2}, {"Charlie",3}};
// same loop, with auto and a for loop
for (auto it = Student.begin(); it != Student.end(); ++it)
std::cout << it->first << " : " << it->second << std::endl;
return 0;
}
Output:
Alex : 1 Charlie : 3 Joe : 2
If you only want to read the map and never change it, use cbegin() and cend() in place of begin() and end(). They give you a const iterator, and the compiler will stop you if you try to change a value by accident.
If you are already comfortable iterating through simple containers like vectors, that skill will make working with maps easier. For a quick refresher on container initialization and iteration, see Initializing a vector in C++.
How To Use Range-Based "For Loops" For C++ Map Iteration?
The range-based 'for' loop is used for iterating over a map and an unordered map. For this, we use the 'auto' keyword. The code provided below explains the same. Have a look!
#include <iostream>
#include <map>
using namespace std;
int main()
{
int freq[] = {1,2,3,5,6,2,2,1,5};
int n = sizeof(freq) / sizeof(freq[0]);
// create a map to find element frequency
map<int, int> elementFreq;
for (int i = 0; i < n; i++)
elementFreq[freq[i]]++;
// using auto keyword to iterate and find frequency of each element
cout << "Element Frequency" << endl;
for (auto i : elementFreq)
cout <<"Frequency of "<< i.first << " is " << i.second << endl;
return 0;
}
Explanation Of The Program:
- We have an array of integers named freq having repeating numbers.
- We go through the array and add each number to the 'elementFreq' map as a key. The value counts how many times that number appears.
- Using the auto keyword, we then iterate over the map and print the frequency of each element.
The result of the above code is given below. By looking at it, we will see that we have successfully performed our task.
Output:
Element Frequency Frequency of 1 is 2 Frequency of 2 is 3 Frequency of 3 is 1 Frequency of 5 is 2 Frequency of 6 is 1
Structured Bindings: The Cleanest Way (C++17)
Writing i.first and i.second everywhere works, but the names tell you nothing. Starting with C++17, you can give the key and the value their own names right inside the loop. This is called a structured binding.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string, int> Student = {{"Alex", 1}, {"Joe", 2}, {"Charlie", 3}};
// each pair is unpacked into two named variables
for (const auto& [name, id] : Student)
cout << name << " : " << id << endl;
return 0;
}
Output:
Alex : 1 Charlie : 3 Joe : 2
Now the loop reads almost like a sentence: for every name and id in Student. If your compiler shows a warning or an error on this line, it is probably set to an older standard. Add -std=c++17 to your g++ command, or change the language standard in your IDE's project settings.
Can We Iterate An unordered_map The Same Way?
Many of you may wonder, "Can we iterate in unordered_map C++?" Absolutely! The same loop works with unordered_map in C++, although the order of each element may be random. Here is the Student example again, with only the container changed.
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
int main()
{
unordered_map<string, int> Student = {{"Alex", 1}, {"Joe", 2}, {"Charlie", 3}};
// exactly the same loop as for a map
for (const auto& [name, id] : Student)
cout << name << " : " << id << endl;
return 0;
}
Output (on our machine):
Charlie : 3 Joe : 2 Alex : 1
This time the names are not in alphabetical order, and not in insertion order either. On your computer, the order may come out differently. So, never write code that depends on the order of an unordered_map. If the order matters, use a map.
How To Traverse A Map Using “std::for_each” And A Lambda Function?
We can also iterate over a map in C++ by using the lambda function and the for_each method. In this case, the lambda function will act as a callback. Let's see the code given below to understand this.
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
int main()
{
// create a map named Student and insert the elements in it
std::map<std::string, int> Student = {{"Alex", 1}, {"Joe", 2}, {"Charlie",3}};
// Iterating over all elements of the map till map end.
std::for_each(
Student.begin(), Student.end(),
[](const std::pair<const std::string, int>& p) {
std::cout << p.first << " has ID " << p.second << std::endl;
});
return 0;
}
Explanation Of The Program:
- We have a map that contains student names and ID numbers as key and value pairs.
- begin() and end() are member functions. They return an iterator to the first element and to the theoretical element following the last element.
- Next, we have called for_each with a lambda expression to go from the start to the end of the map. To do this, we need to include the <algorithm> header file.
- This lambda expression acts as a callback to receive each map entry and finally prints it as the output.
Look closely at the type the lambda receives: const std::pair<const std::string, int>&. The key inside a map is always const. If you leave out that inner const, the code still compiles, but it quietly makes a copy of every pair. To stay safe, you can simply write const auto& p (C++14 and later).
Tip: To avoid writing std::string, std::cout, or std::map, or any other place where you have to use std, you can write using namespace std; at the beginning of your code.
Check out the output for this code below to see if all the elements are printed or not.
Output:
Alex has ID 1 Charlie has ID 3 Joe has ID 2
We see that 'Joe', having ID 2, is printed as the last element. This is because the keys are stored in ascending or alphabetical order in the binary tree.
How To Do Reverse Iteration In C++ Maps?
For containers like maps, we can traverse the map from end to beginning. This can be used when we need to process the data in reverse order. So, how to traverse a map from the end in C++?
Let's take a look at it with the coding example.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
// create a map named myMap and insert the elements in it
map<string, int> myMap = {{"Alex", 1}, {"Joe", 2}, {"Charlie",3}};
// Reverse iterating using reverse iterators
std::cout << "-------Reverse iteration of the map----------" << std::endl;
for (auto it = myMap.rbegin(); it != myMap.rend(); ++it) {
std::cout << it->first << " has ID " << it->second << "." << std::endl;
}
return 0;
}
Explanation Of The Program:
- In this case, we have a map, myMap, that has some data stored in the form of key and value pairs. The key is of string type for the names, and the value is an int for the ID numbers.
- For iterating in reverse order, we have to use the STL reverse iterators. These are the rbegin() iterator pointing to the last data value and the rend() iterator pointing before the first data value.
- By using the for loop, we will perform the traversing of the map in reverse or descending order.
The result for this program is given below. We will be able to see the names of the students in decreasing order.
Output:
-------Reverse iteration of the map---------- Joe has ID 2. Charlie has ID 3. Alex has ID 1.
One thing that surprises students here: we still write ++it, not --it. A reverse iterator already knows it is walking backwards, so "next" for it means the previous element of the map.
How To Change Values While Iterating Over A Map?
Printing a map is only half of the story. In assignments, you will often need to update every value, for example, to add 5 bonus points to each student. This is where one missing character causes a bug that produces no error at all. Have a look at the code below.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string, int> score = {{"Alex", 70}, {"Charlie", 85}, {"Joe", 90}};
// Attempt 1: no & sign, so p is a copy of each pair
for (auto p : score)
p.second += 5;
cout << "After the loop without &: ";
for (const auto& p : score)
cout << p.second << " ";
cout << endl;
// Attempt 2: with &, p is the real pair inside the map
for (auto& p : score)
p.second += 5;
cout << "After the loop with &: ";
for (const auto& p : score)
cout << p.second << " ";
cout << endl;
return 0;
}
Output:
After the loop without &: 70 85 90 After the loop with &: 75 90 95
The first loop ran without any complaint, but nothing changed. Without the & sign, 'p' is a copy of each pair. We added 5 to the copy, and the copy was thrown away. In the second loop, auto& makes 'p' the real pair inside the map, so the change stays.
You can change the value, but you can never change the key. If you try something like p.first = "Sam"; inside that loop, the compiler refuses:
main.cpp:9:19: error: no match for 'operator=' (operand types are 'const std::__cxx11::basic_string<char>' and 'const char [4]')
Look at the word "const" in front of the string type in that message. It is telling you the key is constant. The map uses the key to decide where the pair sits in the tree, so it does not let you edit it in place. To "rename" a key, erase the old pair and insert a new one.
How To Remove Elements While Iterating Over A Map?
This is a very common source of crashes with maps. Suppose we want to delete every student who scored below 50. Students usually call score.erase(it) inside a normal for loop and then let the loop do ++it. But once an element is erased, the iterator that pointed to it is dead. Moving a dead iterator forward is undefined behavior. The program may crash, may skip elements, or may look fine on your laptop and fail on the grader.
The safe way is to use the iterator that erase() gives back.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string, int> score = {{"Alex", 45}, {"Charlie", 85}, {"Joe", 38}, {"Maya", 91}};
// remove every student who scored below 50
for (auto it = score.begin(); it != score.end(); )
{
if (it->second < 50)
it = score.erase(it); // erase() hands back the next valid iterator
else
++it; // only move forward when nothing was erased
}
for (const auto& [name, points] : score)
cout << name << " : " << points << endl;
return 0;
}
Output:
Charlie : 85 Maya : 91
Explanation Of The Program:
- The third part of the for loop is left empty on purpose. We decide inside the loop how to move forward.
- If the score is below 50, erase() removes the pair and returns an iterator to the element after it. We store that in 'it'.
- Otherwise, we move forward with ++it as usual.
Also, do not erase inside a range-based for loop and then keep looping. That loop hides its iterator from you, so you have no way to repair it after the erase.
If your compiler supports C++20, there is a shorter way. The erase_if function takes the map and a condition, and removes every pair that matches.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string, int> score = {{"Alex", 45}, {"Charlie", 85}, {"Joe", 38}, {"Maya", 91}};
// C++20: one line does the whole job
erase_if(score, [](const auto& p) { return p.second < 50; });
for (const auto& [name, points] : score)
cout << name << " : " << points << endl;
return 0;
}
Output:
Charlie : 85 Maya : 91
How To Iterate Over Only The Keys Or Only The Values?
Sometimes you need just the names, or just the numbers. With any version of C++, the simple way is to run the normal loop and use only the half you need.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string, int> Student = {{"Alex", 1}, {"Joe", 2}, {"Charlie", 3}};
cout << "Keys: ";
for (const auto& p : Student)
cout << p.first << " "; // just leave out p.second
cout << endl;
return 0;
}
Output:
Keys: Alex Charlie Joe
From C++20, the <ranges> header gives you two ready-made views for this, views::keys and views::values.
#include <iostream>
#include <map>
#include <string>
#include <ranges>
using namespace std;
int main()
{
map<string, int> Student = {{"Alex", 1}, {"Joe", 2}, {"Charlie", 3}};
cout << "Keys: ";
for (const auto& name : views::keys(Student))
cout << name << " ";
cout << endl;
cout << "Values: ";
for (int id : views::values(Student))
cout << id << " ";
cout << endl;
return 0;
}
Output:
Keys: Alex Charlie Joe Values: 1 3 2
The values come out as 1 3 2 because they follow the order of their keys (Alex, Charlie, Joe), not their own order. A map is sorted by key only.
How To Iterate Nested Maps, Maps Of Vectors, And Multimaps?
In real coursework, the value is often not a single number. It can be a vector, or even another map. The rule is simple: one loop for each level. The outer loop walks the map, and the inner loop walks whatever is stored as the value.
#include <iostream>
#include <map>
#include <string>
#include <vector>
using namespace std;
int main()
{
// each student has a list of quiz scores
map<string, vector<int>> quizzes = {
{"Alex", {80, 92, 75}},
{"Joe", {60, 71}}
};
for (const auto& [name, scores] : quizzes) // outer loop: one student
{
cout << name << ": ";
for (int s : scores) // inner loop: that student's scores
cout << s << " ";
cout << endl;
}
// a map inside a map: course -> (student -> grade)
map<string, map<string, char>> grades = {
{"CS101", {{"Alex", 'A'}, {"Joe", 'B'}}},
{"MATH201", {{"Alex", 'B'}}}
};
for (const auto& [course, roster] : grades)
for (const auto& [name, grade] : roster)
cout << course << " - " << name << " - " << grade << endl;
return 0;
}
Output:
Alex: 80 92 75 Joe: 60 71 CS101 - Alex - A CS101 - Joe - B MATH201 - Alex - B
A multimap is a map that allows the same key more than once. The loop does not change at all. If you want only the entries of one key, use equal_range(). It returns a pair of iterators marking where that key starts and where it ends.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
multimap<string, string> clubs = {
{"Alex", "Chess"}, {"Joe", "Robotics"}, {"Alex", "Debate"}
};
// the loop is the same; the same key simply shows up more than once
for (const auto& [name, club] : clubs)
cout << name << " : " << club << endl;
// only the entries for one key
cout << "Alex is in: ";
auto range = clubs.equal_range("Alex");
for (auto it = range.first; it != range.second; ++it)
cout << it->second << " ";
cout << endl;
return 0;
}
Output:
Alex : Chess Alex : Debate Joe : Robotics Alex is in: Chess Debate
How To Iterate Over Only A Part Of A Map?
You do not always have to start at begin(). Because a map is sorted, you can jump to a key and start walking from there. The lower_bound() function returns an iterator to the first key that is not less than the one you give it. The same program also shows how to keep a position counter, since a map has no index of its own.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<int, string> seat = {{10, "Alex"}, {20, "Charlie"}, {30, "Joe"}, {40, "Maya"}};
// start at the first key that is 20 or more, and go to the end
cout << "Seats 20 and up: ";
for (auto it = seat.lower_bound(20); it != seat.end(); ++it)
cout << it->first << "=" << it->second << " ";
cout << endl;
// only the keys from 15 up to (but not including) 35
cout << "Seats 15 to 34: ";
auto stop = seat.lower_bound(35);
for (auto it = seat.lower_bound(15); it != stop; ++it)
cout << it->first << "=" << it->second << " ";
cout << endl;
// keep a position counter, since a map has no index
int position = 1;
for (const auto& [number, name] : seat)
{
cout << position << ". " << name << endl;
position++;
}
return 0;
}
Output:
Seats 20 and up: 20=Charlie 30=Joe 40=Maya Seats 15 to 34: 20=Charlie 30=Joe 1. Alex 2. Charlie 3. Joe 4. Maya
Finding the starting point takes O(log n) time, which is much faster than looping from the beginning and skipping the keys you do not want.
Comparison Table: All The Ways To Iterate A Map In C++
| Method | Needs | Can change values? | Use it when |
|---|---|---|---|
Range-based for with auto& p | C++11 | Yes (with &) | You want a simple loop that works on any C++11 compiler |
Range-based for with auto& [key, value] | C++17 | Yes (with &) | Everyday code. The most readable choice |
| Iterator with begin() and end() | C++11 | Yes | You need to erase while looping, or start from the middle |
| cbegin() and cend() | C++11 | No | You only read the map and want the compiler to guard it |
| std::for_each with a lambda | C++11 | Yes (take the pair by reference) | You already have a function or lambda to apply to each pair |
| rbegin() and rend() | C++11 | Yes | You need the largest key first |
| views::keys and views::values | C++20 | Values only | You need only one half of each pair |
| erase_if | C++20 | Removes pairs | You want to delete every pair that matches a condition |
All of these visit every element once, so they all take O(n) time. For a class assignment, you will not be able to measure a speed difference between them. Pick the one that is easiest to read.
A Mentor Guide: How To Choose The Right Map Iteration Method?
When students first learn that there are multiple ways to iterate over a map in C++, they often get overwhelmed. Most students ask which one they are supposed to use. The truth is that you don’t need all of them every time.
To help you in this case, we have developed a simple guide.
- If you are just starting to learn maps, use a ‘range-based for loop’. It is the cleanest and easiest to read. Here, you don’t need to manually handle iterators.
- For working on older C++ codes, you will likely use the iterator method. It is important to understand it so you can work on real-world code confidently.
- If your compiler supports C++17 or later, use structured bindings like ‘auto [key, value]’. It makes your code shorter and easier to understand.
- For modifying values while iterating on a map, use ‘auto&’. Without it, you change a copy and the map stays the same.
- If you need reverse order, use ‘rbegin()’ and ‘rend()’ instead of normal iterators.
- For removing elements while iterating, use the iterator loop with ‘it = m.erase(it)’, or ‘erase_if’ in C++20.
- For writing very functional-style code, you can use ‘std::for_each()’ with a lambda. But this one is not for beginners; a normal loop is usually clearer.
Note: From my experience teaching students, the range-based loop works best in 90% of learning situations. Focus on understanding how iteration works first. Then explore the advanced styles.
Common Mistakes Students Make With C++ Map Iteration:
Over the years, I have taught C++ to hundreds of students, and I have noticed the same mistake patterns when it comes to iterating over ‘std::map’. If you want to avoid them, go through the following list.
- Many students forget that a ‘std::map’ stores the key and value pairs, not just single values. So they try to treat it like a vector or array.
- Oftentimes, students mix up the ‘it->first’ and ‘it->second,’ forgetting that first is the key and second is the value.
- Sometimes, students try to modify the key inside the loop, not realizing that map keys are const and cannot be changed once inserted.
- A common mistake is writing the wrong iterator type, mainly when the map has complex template types.
- Many students forget to use ‘auto’ when appropriate, which makes their code longer and increases the chance of typing errors.
- Some use a range-based for loop but forget to use a reference (&), which means they accidentally work on a copy instead of the original map elements.
- Some students erase an element inside the loop and then keep using the same iterator, which leads to crashes that are hard to trace.
Two more mistakes deserve a closer look, because the first one gives a confusing compiler error and the second one gives no error at all.
Using '<' in the loop condition. With vectors, many students write it < v.end(). With a map, a loop like for (auto it = m.begin(); it < m.end(); ++it) does not compile. The error begins like this:
main.cpp:8:33: error: no match for 'operator<' (operand types are 'std::_Rb_tree_iterator<std::pair<const int, std::__cxx11::basic_string<char> > >' and 'std::map<int, std::__cxx11::basic_string<char> >::iterator' {aka ...
Map iterators cannot be compared with '<'. Always write it != m.end().
Reading with the square brackets. The [] operator is not a safe way to check a key. If the key is missing, it creates it.
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string, int> score = {{"Alex", 70}, {"Joe", 90}};
cout << "Size before: " << score.size() << endl;
// looks like a harmless check, but [] creates the key if it is missing
if (score["Maya"] > 50)
cout << "Maya passed" << endl;
cout << "Size after: " << score.size() << endl;
for (const auto& [name, points] : score)
cout << name << " : " << points << endl;
return 0;
}
Output:
Size before: 2 Size after: 3 Alex : 70 Joe : 90 Maya : 0
We only wanted to check Maya's score, and now the map has a new student with 0 points. When you print the map later, an extra row appears, and it is hard to tell where it came from. To check a key without creating it, use score.find("Maya") != score.end(), or score.count("Maya").
What Are Some Best Practices For Iteration Over Maps In C++?
It is necessary to follow the best practices and conventions while writing any program in C++ or other programming languages. While working with maps, we should carefully consider healthy coding practices so that we are able to write clear and concise code.
Here are some best practices that you can follow to build effective programs using maps.
- Use Range-Based Loops - This is one of the cleanest techniques for map iterations. It simplifies the process and handles the iterator pointing to the elements on its own.
- Use 'const' Keyword - We can use the const keyword to avoid unnecessary modifications in maps while we are traversing. If you change something by mistake, the compiler catches it before the program ever runs.
- Avoid Unnecessary Copies by Using References - We can improve the performance of the code and handle a large map with complex data types by using references like auto& instead of simple auto. This matters most when the values are big, like long strings or vectors.
- Do Not Remove Keys Inside A Range-Based Loop - If you need to delete elements, switch to the iterator loop shown in the erase section.
Ordered containers like a map may remind you of certain tree-like behaviors, especially when order matters. To understand similar traversal ideas in data structures, check out Tree traversal methods, which give insight into ordered access patterns.
Conclusion
Learning “How to Iterate Maps in C++” is an important step in becoming comfortable with the Standard Template Library.
While some approaches, like range-based loops, are simple and beginner-friendly, others, such as working directly with Iterators, require a deeper understanding of how maps store and manage key and value pairs.
Keep practicing with small examples, experiment with modifying values, and pay attention to compiler feedback. That is how you move from just writing code to truly understanding C++.
Takeaways:
- There are multiple ways to traverse a map in C++. We can use loops, STL iterators, lambda functions, and reverse iterators as well.
- If you want to store data using specific criteria, a map may be suitable for you. In computer science, the keys in this structure are stored in a balanced tree in increasing order.
- Use auto& when you want to change values, and use the iterator returned by erase() when you want to remove elements inside a loop.
- Remember to use coding best practices while implementing maps so that your program is optimized and efficient.
- Iterating over a map takes O(n) time, whereas insertion and lookup take O(log n) due to the tree structure.
Frequently Asked Questions:
1) Why can't we use '<' to compare map iterators?
Map iterators are bidirectional iterators, not random-access iterators. This means they can move forward and backward, but not jump positions. That’s why you must use ‘!=’ instead of ‘<’ in loops.
2) Why do we use 'auto' with map iterators?
Map iterator types can be long and complex, especially with nested templates. Using 'auto' reduces errors and makes the code cleaner and easier to read. It also helps you avoid mismatching the exact iterator type.
3) Does a map allow duplicate keys?
No, std::map does not allow duplicate keys. If you assign to the same key again with the [] operator, it will overwrite the existing value. The insert() function, on the other hand, leaves the old value as it is. If you need duplicate keys, you have to use the ‘std::multimap’.
4) In what order does a C++ map iterate?
A std::map always iterates in ascending order of its keys. Numbers go from smallest to largest, and strings go in alphabetical order. The order in which you inserted the elements does not matter. An unordered_map has no guaranteed order at all.
5) Can I iterate over a map using an index like i = 0, 1, 2?
No. A map has no index, so m[0] does not mean "the first element." It means "the value stored under the key 0." If you need a position number while looping, keep your own counter variable and increase it inside the loop.
6) Is it safe to erase elements from a map while iterating?
Yes, if you do it the right way. Use an iterator loop and write it = m.erase(it) when you remove an element, and ++it when you do not. Erasing inside a range-based for loop and then continuing the loop is not safe.
7) Which C++ version do I need for 'auto [key, value]'?
Structured bindings need C++17 or later. With g++, compile using the -std=c++17 flag. If your course requires C++11 or C++14, use 'auto& p' with p.first and p.second instead.

