Vector in C++ STL
Written and reviewed by Gagan Bhardwaj · Senior IT Faculty · 15+ years’ experience
What Is std::vector in C++?
std::vector<T> is the standard growable sequence container. For ordinary element types, it stores elements contiguously like an array, but manages storage and lifetime automatically. Its size can change at runtime.
#include <vector>
std::vector<int> marks{78, 91, 84};| Property | Vector guarantee |
|---|---|
| Indexed access | Constant time |
| Insert/erase at end | Amortized constant time for insertion |
| Insert/erase in middle | Linear time |
| Storage | Contiguous for T other than bool |
| Ownership | Elements and storage released automatically |
Use std::array for a fixed compile-time size and std::deque when efficient operations at both ends are essential. For the wider decision, see vector versus map.
Creating and Initializing Vectors
std::vector<int> empty; // size 0
std::vector<int> five_zeros(5); // 0 0 0 0 0
std::vector<int> four_sevens(4, 7); // 7 7 7 7
std::vector<int> values{5, 10, 15}; // initializer list
std::vector copy = values; // class template deduction
std::vector<int> part(values.begin(), values.begin() + 2);Parentheses and braces mean different things. vector<int>(5, 10) contains five copies of 10, while vector<int>{5, 10} contains two elements: 5 and 10.
A vector owns values, not references. Store a lightweight record type rather than parallel vectors that can become misaligned:
struct Student {
std::string name;
int mark;
};
std::vector<Student> students{{"Aman", 78}, {"Sara", 91}};Include every directly used header, here <vector> and <string>. Avoid using namespace std; in headers and teaching examples.
Safe Element Access
| Operation | Use | Empty/out-of-range behavior |
|---|---|---|
v[i] | Known-valid index | No bounds check |
v.at(i) | Checked index | Throws std::out_of_range |
v.front() | First element | Requires non-empty vector |
v.back() | Last element | Requires non-empty vector |
v.data() | Pointer to contiguous range | Do not dereference for empty range |
if (!marks.empty()) {
std::cout << marks.front() << ' ' << marks.back();
}
try {
std::cout << marks.at(user_index);
} catch (const std::out_of_range&) {
std::cerr << "Invalid index\n";
}Use std::size_t or an appropriate container size type for indexes. When reverse loops are needed, avoid unsigned underflow; reverse iterators are often clearer.
Essential Vector Methods
| Method | Effect |
|---|---|
push_back(value) | Copy/move a value to the end |
emplace_back(args...) | Construct an element at the end |
pop_back() | Remove last element; vector must not be empty |
insert(pos, value) | Insert before an iterator position |
erase(pos/range) | Remove one element or a range |
clear() | Destroy all elements; capacity need not shrink |
assign(...) | Replace the contents |
swap(other) | Exchange contents and capacity |
marks.push_back(96);
marks.emplace_back(88);
marks.insert(marks.begin() + 1, 80);
marks.erase(marks.begin() + 2);
// C++20: remove every failing mark and return count removed
const auto removed = std::erase_if(marks, [](int m) { return m < 40; });pop_back() returns nothing. Read back() first if you need the value. Prefer emplace_back when constructor arguments are available, but do not assume it is automatically faster than moving an already-created object.
Size, Capacity, reserve and resize
std::vector<int> values;
values.reserve(100); // capacity at least 100, size still 0
values.push_back(7); // size becomes 1
values.resize(4); // size 4: appends three value-initialized zeros| Member | Meaning |
|---|---|
size() | Number of live elements |
capacity() | Elements current storage can hold before reallocation |
reserve(n) | Request capacity of at least n; size unchanged |
resize(n) | Change number of elements |
shrink_to_fit() | Non-binding request to reduce capacity |
reserve(100), values[50] is invalid because capacity is not size. Add elements or resize before indexing.Reserve when a reliable approximate final size is known. Calling reserve before every push_back can defeat geometric growth and worsen performance. Growth factor is implementation-specific; write against the capacity guarantee, not an assumed doubling rule.
Iteration, Algorithms and Invalidation
for (int mark : marks) { // copy each int
std::cout << mark << ' ';
}
for (const Student& student : students) { // no record copy
std::cout << student.name << '\n';
}
std::sort(marks.begin(), marks.end());Vector iterators are random-access and contiguous iterators, so standard algorithms such as sort, binary_search and lower_bound work efficiently when their preconditions are met.
- Reallocation invalidates every iterator, pointer and reference to elements, including the past-the-end iterator.
- If insertion does not reallocate, handles before the insertion position remain valid; those at or after it are invalidated.
- Erase invalidates handles at or after the erased position.
reserveinvalidates handles only if it reallocates.
auto it = marks.begin();
marks.push_back(99); // it may now be invalid
it = marks.begin(); // reacquire before useContinue with iterators and STL algorithms.
Complete Practical Program with Verified Output
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> marks;
marks.reserve(6);
for (int mark : {72, 88, 65, 91, 88}) {
marks.push_back(mark);
}
const int total = std::accumulate(marks.begin(), marks.end(), 0);
const auto highest = *std::max_element(marks.begin(), marks.end());
std::sort(marks.begin(), marks.end());
std::cout << "Sorted:";
for (int mark : marks) std::cout << ' ' << mark;
std::cout << std::fixed << std::setprecision(1)
<< "\nAverage: " << total / static_cast<double>(marks.size())
<< "\nHighest: " << highest;
}The vector owns five integers. Reserving six positions avoids reallocation during these insertions but creates no elements. The average uses floating-point division; integer division would incorrectly discard the decimal part.
Common Mistakes, Practice and Review
| Mistake | Correction |
|---|---|
Index equals size() | Last valid index is size()-1 for non-empty vector |
| Indexing after reserve only | push/resize first |
| Calling front/back/pop on empty vector | Check empty() |
| Keeping iterator across growth | Reacquire after possible reallocation |
| Expecting clear to free capacity | Capacity may remain for reuse |
| Using vector of raw owning pointers | Store values or owning smart pointers |
| Parallel vectors for one record | Use vector<Record> |
Practice: (1) remove duplicate marks using sort–unique–erase, (2) store Student records and sort by descending mark, (3) demonstrate size/capacity before and after reserve, (4) erase all negative values safely, and (5) compare checked at() with [].
- Did you include
<vector>directly? - Is the index provably valid?
- Are empty-container preconditions handled?
- Is capacity being confused with size?
- Could mutation invalidate a saved handle?
- Are algorithms given valid ranges and preconditions?
Authoritative References
- C++ Working Draft: std::vector
- C++ Working Draft: Sequence Containers
- C++ Working Draft: Container Requirements
Storage, complexity, reserve/resize and invalidation statements were checked against the current working draft. For STL architecture, read the complete STL guide.
Frequently Asked Questions
What is a vector in C++?
What is the difference between vector size and capacity?
What is the difference between reserve and resize?
Should I use vector operator[] or at()?
When does a vector invalidate iterators and references?
C++ में std::vector क्या है?
std::vector<T> growable sequence container है। Ordinary types में elements contiguous रहते हैं, array जैसी indexing मिलती है और memory/lifetime automatic manage होती है।
#include <vector>
std::vector<int> marks{78,91,84};| Property | Guarantee |
|---|---|
| Index access | O(1) |
| End insertion | Amortized O(1) |
| Middle insert/erase | O(n) |
| Storage | vector<bool> छोड़कर contiguous |
Vector Create और Initialize करें
std::vector<int> empty;
std::vector<int> five_zeros(5);
std::vector<int> four_sevens(4,7);
std::vector<int> values{5,10,15};
std::vector copy=values;vector<int>(5,10) पांच बार 10 रखता है, जबकि {5,10} दो values रखता है। Related fields के parallel vectors के बजाय record रखें:
struct Student{std::string name;int mark;};
std::vector<Student> students{{"Aman",78},{"Sara",91}};Direct headers include करें और headers/examples में using namespace std; avoid करें।
Elements Safely Access करें
| Method | Use |
|---|---|
v[i] | No bounds check |
v.at(i) | Invalid पर out_of_range |
front() | First, vector non-empty हो |
back() | Last, vector non-empty हो |
data() | Contiguous range pointer |
if(!marks.empty()) std::cout<<marks.front();
try{ std::cout<<marks.at(user_index); }
catch(const std::out_of_range&){
std::cerr<<"Invalid index\n";
}Last valid index non-empty vector में size()-1 है। Unsigned reverse loop में underflow से बचें।
Essential Vector Methods
| Method | Effect |
|---|---|
| push_back | End पर value |
| emplace_back | End पर construct |
| pop_back | Last remove; empty नहीं |
| insert | Position से पहले insert |
| erase | Element/range remove |
| clear | All elements destroy, capacity रह सकती है |
| swap | Contents/capacity exchange |
marks.push_back(96);
marks.emplace_back(88);
marks.insert(marks.begin()+1,80);
marks.erase(marks.begin()+2);
auto removed=std::erase_if(marks,
[](int m){return m<40;}); // C++20pop_back value return नहीं करता। Already-created object में move और emplace के बीच automatic speed assumption न करें।
Size, Capacity, reserve और resize
std::vector<int> values;
values.reserve(100); // size 0
values.push_back(7); // size 1
values.resize(4); // 7 0 0 0size(): live elements।capacity(): reallocation से पहले storage limit।reserve(n): capacity request, size unchanged।resize(n): element count change।shrink_to_fit(): non-binding request।
Known final size पर एक बार reserve उपयोगी है; हर push से पहले reserve growth strategy खराब कर सकता है। Doubling guaranteed नहीं है।
Iteration और Invalidation
for(int mark:marks) std::cout<<mark<<' ';
for(const Student& s:students) std::cout<<s.name;
std::sort(marks.begin(),marks.end());- Reallocation सभी iterators/pointers/references invalid करती है।
- No reallocation में insert point से आगे handles invalid।
- Erase position और उसके बाद handles invalid।
- reserve केवल reallocation होने पर invalidates।
auto it=marks.begin();
marks.push_back(99); // it invalid हो सकता है
it=marks.begin();iterators और algorithms आगे पढ़ें।
Complete Practical Program और Output
std::vector<int> marks;
marks.reserve(6);
for(int m:{72,88,65,91,88}) marks.push_back(m);
int total=std::accumulate(marks.begin(),marks.end(),0);
int highest=*std::max_element(marks.begin(),marks.end());
std::sort(marks.begin(),marks.end());Reserve ने elements नहीं बनाए, केवल insertion के लिए capacity दी। Total 404 है और floating-point division से average 80.8 आया।
Mistakes, Practice और Review
| Mistake | Correction |
|---|---|
| Index == size | Out of range |
| reserve के बाद index | push/resize करें |
| Empty front/back/pop | empty check |
| Growth के बाद iterator | Reacquire |
| clear frees capacity | Capacity रह सकती है |
| Raw owning pointers | Values/smart owners |
Practice: duplicates remove करें; Student records mark के अनुसार sort करें; reserve से पहले/बाद size-capacity दिखाएं; negative values erase करें; at और [] compare करें।
- Header included?
- Index valid?
- Empty case?
- Size/capacity clear?
- Invalidation checked?
- Algorithm preconditions valid?
Authoritative संदर्भ
Complexity, reserve/resize और invalidation current working draft से verified हैं। Complete STL guide भी पढ़ें।