C++ vector reserve vs resize: When to Use Which (Complete Guide)
이 글의 핵심
A practical guide to C++ vector reserve vs resize: capacity vs size, benchmarks, and patterns.
Contiguous dynamic arrays (like std::vector) are the usual way to implement the “array” side of arrays and lists—this article focuses on capacity vs length inside that model.
Introduction: “Should I use reserve or resize?"
"Don’t both make the vector bigger?”
In C++, vector::reserve and resize do completely different things. reserve only increases capacity; resize changes size and initializes elements.
std::vector<int> vec;
// reserve: capacity only
vec.reserve(100);
std::cout << vec.size() << '\n'; // 0
std::cout << vec.capacity() << '\n'; // 100
// resize: size + initialization
vec.resize(100);
std::cout << vec.size() << '\n'; // 100
std::cout << vec.capacity() << '\n'; // 100
This article covers:
- reserve vs resize
- Performance comparison
- Usage scenarios
- Practical tips
Table of contents
1. reserve vs resize
reserve: capacity only
std::vector<int> vec;
vec.reserve(5); // capacity at least 5
std::cout << vec.size() << '\n'; // 0 (unchanged)
std::cout << vec.capacity() << '\n'; // 5
// vec[0] = 42; // undefined behavior (size is 0)
vec.push_back(10); // OK
std::cout << vec.size() << '\n'; // 1
resize: size change + initialization
std::vector<int> vec;
vec.resize(5); // size 5, value-initialized to 0
std::cout << vec.size() << '\n'; // 5
std::cout << vec.capacity() << '\n'; // at least 5
vec[0] = 42; // OK
std::cout << vec[0] << '\n'; // 42
std::cout << vec[1] << '\n'; // 0 (initialized)
Comparison table
| Aspect | reserve(n) | resize(n) |
|---|---|---|
| size | Unchanged | becomes n |
| capacity | at least n | at least n |
| Initialization | None | default value |
| Index access | Only within size | Yes |
| push_back | Yes | Yes |
2. Performance
Benchmark: push_back
#include <benchmark/benchmark.h>
// No reserve
static void BM_PushBack_NoReserve(benchmark::State& state) {
for (auto _ : state) {
std::vector<int> vec;
for (int i = 0; i < 1000000; ++i) {
vec.push_back(i);
}
}
}
BENCHMARK(BM_PushBack_NoReserve);
// With reserve
static void BM_PushBack_Reserve(benchmark::State& state) {
for (auto _ : state) {
std::vector<int> vec;
vec.reserve(1000000);
for (int i = 0; i < 1000000; ++i) {
vec.push_back(i);
}
}
}
BENCHMARK(BM_PushBack_Reserve);
// resize
static void BM_Resize(benchmark::State& state) {
for (auto _ : state) {
std::vector<int> vec;
vec.resize(1000000);
for (int i = 0; i < 1000000; ++i) {
vec[i] = i;
}
}
}
BENCHMARK(BM_Resize);
Results (GCC 13, -O3):
BM_PushBack_NoReserve 50 ms (many reallocations)
BM_PushBack_Reserve 10 ms (no reallocations)
BM_Resize 8 ms (fastest)
3. Usage scenarios
reserve: before push_back
// reserve: grow with push_back
std::vector<int> vec;
vec.reserve(1000);
for (int i = 0; i < 1000; ++i) {
vec.push_back(i);
}
resize: index access
// resize: direct indexing
std::vector<int> vec;
vec.resize(1000);
for (int i = 0; i < 1000; ++i) {
vec[i] = i;
}
resize: fill with a value
// resize: initialize to a specific value
std::vector<int> vec;
vec.resize(1000, 42);
std::cout << vec[0] << '\n'; // 42
std::cout << vec[999] << '\n'; // 42
4. Examples
Example 1: reading a file
// reserve: unknown line count
std::vector<std::string> lines;
lines.reserve(1000);
std::ifstream file("data.txt");
std::string line;
while (std::getline(file, line)) {
lines.push_back(line);
}
Example 2: converting from an array
// resize: known size
int arr[100] = {/* ... */};
std::vector<int> vec;
vec.resize(100);
for (int i = 0; i < 100; ++i) {
vec[i] = arr[i];
}
Example 3: 2D matrix
// resize: 2D vector
std::vector<std::vector<int>> matrix;
matrix.resize(10);
for (auto& row : matrix) {
row.resize(20, 0);
}
matrix[5][10] = 42;
Summary
Choosing reserve vs resize
| Situation | Use |
|---|---|
| Growing with push_back | reserve |
| Direct index access | resize |
| Unknown final size | reserve |
| Known size + initialization | resize |
| Avoid reallocations only | resize |
| Need element initialization | resize |
Rules of thumb
- push_back → reserve
- Index access → resize
- Need initialization → resize
- Reallocations only → reserve
Checklist
- If you use push_back, do you reserve?
- If you index, do you resize first?
- Do you need default initialization?
- Is performance critical?
Related reading (internal links)
- C++ vector basics guide
- C++ vector vs list vs deque
- C++ performance optimization
- C++ STL containers guide
Keywords (SEO)
vector reserve, vector resize, reserve vs resize, vector performance, avoid reallocation
Practical tips
Debugging
- Indexing after reserve only (size still 0) is undefined behavior.
- push_back after resize still grows size.
- capacity rarely shrinks without shrink_to_fit.
Performance
- reserve before push_back loops to avoid reallocations.
- Index-heavy code can be faster with resize + assignment.
- If you do not need initialization, prefer reserve + push_back.
Code review
- Check reserve in hot push_back loops.
- Find index writes without prior resize.
- Replace unnecessary resize with reserve when only capacity matters.
Closing
reserve avoids reallocations; resize changes length and initializes.
Takeaways:
- push_back → reserve
- Index access → resize
- Hot paths → reserve
If you use push_back, reserve is the usual way to win performance.
Next: dig deeper in the C++ STL container guides.
Related posts
- Browse the C++ series
- C++ Adapter Pattern
- C++ ADL
- C++ aggregate initialization