Question
How can I iterate over every element in a std::map<std::string, int> when I do not know its keys or values in advance? In particular, how do I access the key and value for each iterator position?
void output(std::map<std::string, int> table)
{
std::map<std::string, int>::iterator it;
for (it = table.begin(); it != table.end(); it++)
{
// How do I access each key and value?
}
}
Short Answer
By the end of this page, you will know that each std::map element is a key-value pair, how to access its .first and .second members, and how to use modern range-based loops safely and clearly.
Concept
std::map<Key, Value> stores key-value pairs. For this map:
std::map<std::string, int> table;
- The key type is
std::string. - The value type is
int. - Each individual map element is effectively a
std::pair<const std::string, int>.
A pair has two named members:
.first— the key.second— the mapped value
Therefore, when an iterator points at an element, dereferencing it (*it) gives access to that pair:
it->first // the string key
it->second // the integer value
The arrow operator is shorthand for dereferencing the iterator and then accessing a member:
(*it).first // equivalent to it->first
(*it).second // equivalent to it->second
Maps are ordered by key. With the default comparator, iteration visits string keys in ascending lexicographical order. This is useful when you need predictable, sorted traversal rather than insertion order.
Mental Model
Think of a std::map as a sorted filing cabinet.
- Every drawer label is a key (
"apples"). - The item count inside that drawer is the value (
4). - An iterator is your finger pointing to one drawer.
When your finger points at a drawer:
it->firstreads its label.it->secondreads or updates what is inside it.
Calling ++it moves your finger to the next drawer in sorted label order.
Syntax and Examples
The classic iterator form accesses the current pair through it:
#include <iostream>
#include <map>
#include <string>
void output(const std::map<std::string, int>& table)
{
for (std::map<std::string, int>::const_iterator it = table.begin();
it != table.end();
++it)
{
std::cout << it->first << ": " << it->second << '\n';
}
}
const std::map<std::string, int>& is used because this function only reads the map:
constprevents accidental modification.&avoids copying the entire map when calling the function.const_iteratormatches a const map and allows reading its elements.
For C++11 and later, a range-based for loop is usually easier to read:
for (const auto& entry : table)
{
std::cout << entry.first << ": " << entry.second << '\n';
}
For C++17 and later, structured bindings give the key and value their own names:
for (const auto& [key, value] : table)
{
std::cout << key << ": " << value << '\n';
}
Example output for a map containing {"banana", 2}, {"apple", 5}, and {"pear", 1} is:
apple: 5
banana: 2
pear: 1
The order is alphabetical by key, not the order in which the values were inserted.
Step by Step Execution
Consider this code:
std::map<std::string, int> scores{
{"Mia", 90},
{"Ava", 95}
};
for (auto it = scores.begin(); it != scores.end(); ++it)
{
std::cout << it->first << " scored " << it->second << '\n';
}
Execution proceeds as follows:
scoresstores two pairs:("Mia", 90)and("Ava", 95).scores.begin()returns an iterator pointing at the first key in sorted order:"Ava".it != scores.end()is true becauseitpoints to a real element.it->firstis"Ava", andit->secondis95; the first line is printed.++itadvances the iterator to the pair for"Mia".- The condition is true again, and the second line is printed.
- Another
++itadvances the iterator toscores.end(), a position just after the last element. - The condition becomes false, so the loop stops.
Output:
Ava scored 95
Mia scored 90
Real World Use Cases
Iterating through a map is useful whenever data is indexed by a unique name, identifier, or code:
- Configuration settings: print or validate settings such as
"theme" -> 2. - Inventory: process product names and stock counts.
- API aggregation: iterate through response headers or request parameters.
- Word-frequency analysis: print each word and its number of occurrences.
- User statistics: walk through user IDs and their scores or balances.
- Reporting: produce a deterministic report because
std::maptraverses keys in sorted order.
Real Codebase Usage
In production C++ code, range-based loops with references are commonly preferred for simple traversal:
for (const auto& [name, count] : inventory)
{
log(name, count);
}
Use const auto& when only reading. It avoids copying each key-value pair, which matters if keys or values are large objects.
When updating mapped values, use a non-const reference to the entry. The key remains immutable through a map iterator:
for (auto& [name, count] : inventory)
{
if (count < 0)
{
count = 0;
}
}
A common validation pattern is to return early when a required key is absent, then use find when you only need one key:
auto it = settings.find("timeout");
if (it == settings.end())
{
return;
}
int timeout = it->second;
Use full iteration when every entry must be processed. Use find when searching for a specific key.
Common Mistakes
Using it.first instead of it->first
An iterator is not the pair itself. This is incorrect:
std::cout << it.first; // Error
Use either form below:
std::cout << it->first;
std::cout << (*it).first;
Dereferencing end()
end() does not point to an element. Never do this:
auto it = table.end();
std::cout << it->second; // Undefined behavior
Only dereference an iterator after confirming it is not equal to end().
Copying the map unnecessarily
The original function parameter copies the entire map:
void output(std::map<std::string, int> table)
For read-only output, prefer:
void output(const std::map<std::string, int>& table)
Trying to modify the key
Map keys are treated as const because changing a key could break the map's sorted structure:
for (auto& entry : table)
{
// entry.first = "new key"; // Error
entry.second += 1; // Valid
}
Using table[key] merely to check for a key
operator[] inserts a new entry if the key is missing:
if (table["unknown"] == 0) { }
Use find or contains instead when you do not want insertion:
if (table.find("unknown") != table.end()) { }
Erasing while using a simple increment loop
Erasing invalidates the iterator being erased. Use the iterator returned by erase:
for (auto it = table.begin(); it != table.end();)
{
if (it->second == 0)
{
it = table.erase(it);
}
else
{
++it;
}
}
Comparisons
| Approach | C++ version | Best use | Access to key and value |
|---|---|---|---|
| Explicit iterator | All modern C++ versions | Erasing entries or manually controlling movement | it->first, it->second |
| Range-based loop | C++11+ | Straightforward traversal | entry.first, entry.second |
| Structured bindings | C++17+ | Clearest read-only or update loops | key, value |
find | All modern C++ versions | Looking up one known key | it->second after checking end() |
std::map and std::unordered_map both store key-value pairs, but their iteration behavior differs:
| Container | Iteration order | Typical lookup behavior | Use when |
|---|---|---|---|
std::map | Sorted by key | O(log n) | You need sorted keys or ordered operations |
std::unordered_map | No guaranteed order | Average O(1) | You primarily need fast key lookups and do not need ordering |
Cheat Sheet
std::map<std::string, int> table;
| Task | Code |
|---|---|
| Get first iterator | auto it = table.begin(); |
| Detect end | it == table.end() |
| Read key | it->first |
| Read or change value | it->second |
| Move forward | ++it |
| Read every entry, C++11+ | for (const auto& entry : table) |
| Name key and value, C++17+ | for (const auto& [key, value] : table) |
| Find one key | auto it = table.find(key); |
Rules to remember:
- Do not dereference
table.end(). - Map keys are immutable through iterators; mapped values can be changed in a non-const map.
- Pass a map as
const std::map<Key, Value>&when a function only reads it. std::mapiterates in sorted key order.
FAQ
How do I get the key and value from a std::map iterator?
Use it->first for the key and it->second for the value.
Why is it->first used instead of it.first?
it is an iterator, which behaves like a pointer to an element. it->first accesses the pair that the iterator points to.
Can I change a value while iterating through a map?
Yes, if the map and iterator are non-const. Assign to it->second or to the value binding in for (auto& [key, value] : map).
Can I change a map key while iterating?
No. A map's keys are immutable through iterators because their order defines the container's internal structure. To change a key, erase the old entry and insert a new one.
Does std::map preserve insertion order?
No. It iterates in sorted order according to its key comparator, ascending order by default.
Should I use it++ or ++it in a map loop?
Prefer ++it. For iterators, postfix increment (it++) may create an unnecessary temporary copy.
Is const auto& [key, value] safe in a range-based loop?
Yes. It creates read-only references to each map entry without copying it. It requires C++17.
What happens if I access table["missing"]?
A new entry with that key is inserted, using a default value such as 0 for int. Use find if you only want to test whether the key exists.
Mini Project
Description
Build a small inventory-report function. A store keeps item names as map keys and stock counts as values. Your function will loop through the entire map, print each item, and calculate the total number of units in stock.
Goal
Display every inventory entry in sorted item-name order and return the total stock count.
Requirements
- Create a
std::map<std::string, int>containing at least three inventory items. - Write a function that accepts the map without copying it.
- Loop through every key-value pair in the map.
- Print each item name and its quantity.
- Return and print the sum of all quantities.
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.