Vectors and Maps
Written and reviewed by Gagan Bhardwaj · Senior IT Faculty · 15+ years’ experience
Vector or Map: Decide from Meaning
std::vector<T> represents an ordered sequence of values in contiguous storage. std::map<Key, T> represents key-value associations ordered by unique keys. They are not interchangeable performance switches; they model different questions:
- “What is the third score?” suggests a sequence and possibly a vector.
- “What score belongs to Sara?” suggests a key-value association and possibly a map.
- “Preserve insertion order and look up names” may need a vector plus an index, or another deliberately designed structure.
| Question | Vector | Map |
|---|---|---|
| Primary identity | Position/index | Key |
| Iteration order | Sequence order | Comparator/key order |
| Storage | Contiguous elements | Node-based ordered association |
| Duplicate identity | Values may repeat | Keys are unique; values may repeat |
Vector Deep Dive: Size, Capacity and Safe Access
#include <vector>
std::vector<int> scores;
scores.reserve(100); // capacity at least 100; size is still 0
scores.push_back(78); // size becomes 1
scores.emplace_back(91); // constructs an element at the end
int first = scores[0]; // no bounds check
int checked = scores.at(1); // throws std::out_of_range if invalidVector supports constant-time indexing and amortized constant-time insertion at the end. “Amortized” means occasional growth may allocate a larger block and move/copy existing elements, while a sequence of push-backs has constant average cost per insertion under the guarantee.
reserve(n) requests capacity for at least n elements but creates none. resize(n) changes the size and creates/removes elements. This is invalid:
std::vector<int> values;
values.reserve(10);
// values[0] = 7; // error: size is still zeroUse push_back, emplace_back or resize before indexing. Read the dedicated C++ vector tutorial for construction and member functions.
Map Deep Dive: Ordered Keys and Lookup
#include <map>
#include <string>
std::map<std::string, int> marks{
{"Sara", 91}, {"Aman", 78}
};
marks.insert_or_assign("Aman", 83);
if (auto it = marks.find("Sara"); it != marks.end()) {
std::cout << it->second;
}
if (marks.contains("Kabir")) { /* C++20 */ }A map maintains elements in the order defined by its comparator (ascending std::less by default). Search, insertion and erasure are logarithmic. The standard specifies behavior and complexity, not a mandatory tree implementation.
Be precise with access:
m[key]returns the value and inserts a value-initialized entry when the key is absent.m.at(key)does not insert and throwsstd::out_of_rangewhen missing.m.find(key)returns an iterator; it works before C++20.m.contains(key)returns a boolean since C++20.try_emplaceavoids constructing the mapped value when the key already exists.
For sets and associative fundamentals, see C++ set and map.
Combined Vector-and-Map Program with Output
#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <vector>
int main() {
std::vector<int> scores{78, 91, 84, 91};
std::sort(scores.begin(), scores.end());
std::cout << "Sorted scores:";
for (int score : scores) std::cout << ' ' << score;
std::map<std::string, int> by_name{
{"Sara", 91}, {"Aman", 78}, {"Kabir", 84}
};
by_name.at("Aman") += 5;
std::cout << "\nBy name:";
for (const auto& [name, score] : by_name) {
std::cout << ' ' << name << ':' << score;
}
}The vector preserves duplicate scores and is sorted by value. The map produces key order, not insertion order: Aman, Kabir, Sara. The structured binding binds each pair as name and score; const auto& avoids copying.
Complexity Comparison and Alternatives
| Operation | vector | map |
|---|---|---|
| Index by position | O(1) | Not supported |
| Append | Amortized O(1) | Not a sequence operation |
| Insert/erase middle | O(n) movement | O(log n) by key |
| Find in unsorted data | O(n) | O(log n) |
| Find in sorted data | O(log n) comparisons with lower_bound | O(log n) |
| Ordered traversal | Sequence/sorted only if maintained | Always comparator order |
| Memory locality | Strong contiguous locality | Node overhead and pointer traversal |
A sorted vector can be excellent for read-heavy small or medium data: compact storage, binary search and fast traversal. Its insertion remains O(n). A map is valuable when ordered keyed updates are frequent and stable element handles matter.
If ordering is irrelevant, consider unordered_map: expected average constant lookup, but worst-case linear behavior, hash requirements, rehashing and no stable sorted iteration. Big-O alone does not decide real speed; benchmark representative data.
Iteration, Mutation and Invalidation
Vector rules that matter
- If an operation changes capacity, all iterators, pointers and references to elements are invalidated.
- Without reallocation, inserting invalidates handles at or after the insertion position; erase invalidates the erased position and everything after it.
reservecan reduce repeated reallocations, but calling a later larger reserve can itself reallocate.
Map rules that matter
- Insertion/emplacement does not invalidate existing iterators and references.
- Erasure invalidates only iterators/references to erased elements.
- Do not dereference
end(); after erase, use the returned next iterator where appropriate.
for (auto it = by_name.begin(); it != by_name.end(); ) {
if (it->second < 40) it = by_name.erase(it);
else ++it;
}In range-for loops, use const auto& for read-only access and auto& when modifying mapped values. A map key is const through its iterator; changing it in place would violate ordering. Erase and insert under the new key instead.
Real Design Patterns
1. Sorted report plus keyed lookup
If an application needs both insertion order and name lookup, a map alone cannot preserve insertion order. One design stores records in a vector and keeps a separate map from key to stable identifier/index. Define how erasure and vector relocation affect the index.
2. Frequency table
std::map<std::string, int> frequency;
for (const std::string& word : words) {
++frequency[word]; // insertion is intentional here
}Here operator[] is ideal because a missing count should begin at zero.
3. Read-mostly flat data
std::vector<std::pair<std::string, int>> records;
std::sort(records.begin(), records.end());
auto it = std::lower_bound(records.begin(), records.end(),
std::pair{std::string{"Sara"}, 0});This can be compact and cache-friendly, but duplicates, comparator semantics and update cost must be designed deliberately. Prefer clear standard containers until profiling demonstrates a need for a more complex dual structure.
Common Mistakes and Review Checklist
| Mistake | Correction |
|---|---|
reserve then index | Use push/resize; capacity is not size |
map[key] for read-only test | Use find/contains/at |
| Assuming map insertion order | Expect comparator/key order |
| Storing vector iterator across growth | Reacquire after possible reallocation |
| Changing a map key in place | Erase and reinsert |
| Calling every logarithmic structure faster | Measure constants, cache and workload |
| Parallel vectors that drift apart | Use a record/struct per entity |
- Is identity positional or keyed?
- Must iteration be sorted, insertion-ordered or arbitrary?
- Are duplicate keys allowed?
- What are the dominant operations?
- Must pointers/references stay valid?
- Can a lookup modify the structure?
- Are empty and missing-key cases tested?
- Are warnings and sanitizers used in development?
Authoritative References
Complexity, access and invalidation claims were checked against the current working draft. These guarantees matter more than a particular vendor's internal implementation.
Frequently Asked Questions
What is the main difference between vector and map in C++?
Is map lookup always faster than vector lookup?
What is the difference between vector reserve and resize?
Why can map operator[] be dangerous for lookup?
Does inserting into std::map invalidate existing iterators?
Vector या Map: Meaning से चुनें
vector<T> contiguous ordered sequence है; map<Key,T> unique ordered keys के साथ associations रखता है। “तीसरा score” positional/vector question है; “Sara का score” keyed/map question है।
| Property | Vector | Map |
|---|---|---|
| Identity | Index | Key |
| Order | Sequence | Comparator/key |
| Storage | Contiguous | Node-based association |
| Duplicates | Values repeat हो सकते हैं | Keys unique |
Vector Deep Dive
std::vector<int> scores;
scores.reserve(100); // capacity, size अभी 0
scores.push_back(78);
scores.emplace_back(91);
int checked=scores.at(1);Index O(1), end insertion amortized O(1)। Growth पर कभी larger block allocate और elements move/copy होते हैं। reserve capacity बदलता है पर elements नहीं बनाता; resize size बदलता और elements बनाता/हटाता है। इसलिए reserve के बाद values[0] तब तक invalid है जब तक size zero है। vector tutorial पढ़ें।
Map Deep Dive
std::map<std::string,int> marks{{"Sara",91},{"Aman",78}};
marks.insert_or_assign("Aman",83);
if(auto it=marks.find("Sara");it!=marks.end())
std::cout<<it->second;
if(marks.contains("Kabir")){ /* C++20 */ }Map comparator order maintain करता और search/insert/erase O(log n) देता है। Standard किसी specific tree implementation को mandate नहीं करता।
m[key]missing key पर default mapped value insert करता है।atinsert नहीं करता; missing पर exception।finditerator देता है;containsC++20 boolean देता है।try_emplaceexisting key में unnecessary mapped construction बचा सकता है।
set/map lesson भी देखें।
Combined Practical Lab और Output
std::vector<int> scores{78,91,84,91};
std::sort(scores.begin(),scores.end());
std::map<std::string,int> by_name{
{"Sara",91},{"Aman",78},{"Kabir",84}};
by_name.at("Aman")+=5;
for(const auto& [name,score]:by_name)
std::cout<<name<<':'<<score<<' ';Vector duplicates रखता और values के अनुसार sort हुआ। Map insertion order नहीं, key order में Aman, Kabir, Sara देता है। const auto& copy बचाता है।
Complexity Comparison
| Operation | vector | map |
|---|---|---|
| Index | O(1) | नहीं |
| Append | Amortized O(1) | Sequence operation नहीं |
| Middle insert | O(n) | O(log n) by key |
| Unsorted find | O(n) | O(log n) |
| Sorted find | lower_bound O(log n) comparisons | O(log n) |
| Locality | Strong | Node overhead |
Read-heavy data में sorted vector compact और fast हो सकता है, पर updates O(n)। Order न चाहिए तो unordered_map average O(1), worst O(n), rehash और unordered iteration देता है। Representative benchmark करें।
Iteration और Invalidation
- Vector capacity change हो तो सभी element iterators/pointers/references invalid।
- No reallocation में insert position और बाद के handles invalid; erase erased और बाद के handles invalid।
- Map insert existing handles valid रखता है; erase केवल erased element के handles invalid करता है।
for(auto it=by_name.begin();it!=by_name.end();){
if(it->second<40) it=by_name.erase(it);
else ++it;
}Read-only range loop में const auto&, mapped value modify करने में auto&। Iterator द्वारा map key const है; key बदलनी हो तो erase/reinsert करें।
Real Design Patterns
Frequency table
std::map<std::string,int> frequency;
for(const std::string& word:words) ++frequency[word];यहां [] intentional है: missing count zero से शुरू होना चाहिए।
Insertion order + lookup
Map अकेला insertion order preserve नहीं करता। Records vector और key-to-index map रख सकते हैं, लेकिन erase/reallocation से index consistency design करनी होगी।
Read-mostly data
Sorted vector<pair<Key,Value>> + lower_bound compact हो सकता है; duplicates, comparator और update cost carefully define करें। Profiling से जरूरत सिद्ध होने तक simple standard design रखें।
Mistakes और Checklist
| Mistake | Correction |
|---|---|
| reserve के बाद index | push/resize करें |
| Read test में map[] | find/contains/at |
| Map insertion order | Key order expect करें |
| Growth के बाद iterator | Reacquire करें |
| Map key in-place change | Erase/reinsert |
| Big-O ही speed | Workload measure करें |
- Positional या keyed identity?
- Required iteration order?
- Duplicates?
- Dominant operations?
- Handle stability?
- Lookup modification allowed?
- Missing/empty tests?
- Warnings/sanitizers?
Authoritative संदर्भ
Complexity, access और invalidation claims current working draft से verified हैं; vendor implementation के बजाय guarantees पर code design करें।