C++ vector Basics | Initialization, Operations, Capacity, and Patterns

C++ vector Basics | Initialization, Operations, Capacity, and Patterns

이 글의 핵심

vector initialization, operations, size vs capacity, reserve/resize, common UB and performance tips for real C++ code.

Introduction: Segfault from vec[10]

“I indexed vec[10] and the program died”

std::vector is the standard dynamic array: contiguous storage, amortized O(1) push at the end, O(1) random access. Think of a bookshelf where slots stay in order and you read slot i in one step—same layout idea as a C array, but the shelf can grow. operator[] does not bounds-check—out-of-range access is undefined behavior (often SIGSEGV).

Analogy: vector is also an expandable drawer cabinet—opening drawer 10 when only three exist is invalid.

Bad:

std::vector<int> vec = {1, 2, 3};
int value = vec[10];  // UB — size is 3

Safer:

int value = vec.at(10);  // throws std::out_of_range
// or
if (10 < vec.size()) { int value = vec[10]; }

Common pitfalls (short)

  • reserve(100) does not change size()—don’t vec[0] until elements exist (push_back, resize, etc.).
  • erase invalidates iterators—use erase return value or erase-remove idiom.
  • Mass push_back without reserve → many reallocations.
  • Range-for while mutating size of the same vector → UB.
  • data() invalidated after reallocation—don’t hold raw pointers across push_back if capacity might grow.
flowchart TB
  subgraph choice["Choosing a container"]
    A[Need dynamic array] --> B{Purpose}
    B -->|index + push back| C["std::vector"]
    B -->|push/pop both ends| D["std::deque"]
    B -->|key lookup| E["map / unordered_map"]
    B -->|sorted unique keys| F["std::set"]
  end
  subgraph vector_opt["vector tips"]
    C --> G["reserve for known size"]
    C --> H["emplace_back to avoid temps"]
  end

Table of contents

  1. Problem scenarios
  2. Initialization
  3. Operations
  4. Capacity
  5. Examples
  6. Common errors
  7. Performance
  8. Best practices
  9. Production patterns
  10. Checklist

1. Problem scenarios

  • Empty CSV rowcells[0] → crash → check empty() first.
  • Erase in loop → use it = vec.erase(it) or erase-remove.
  • Loading millions of rows without reserve → slow → reserve(estimated).
  • Pass by value huge vectors → expensive → const std::vector<T>& or std::vector<T>&&.

2. Initialization

std::vector<int> v1;                 // empty
std::vector<int> v2(5);             // five default-initialized ints
std::vector<int> v3(5, 42);         // five 42s
std::vector<int> v4 = {1,2,3,4,5};  // initializer list

() vs {}: vector<int>(5) is size 5; vector<int>{5} is one element with value 5.


3. Operations

  • push_back / emplace_back
  • insert / erase (O(n) for middle)
  • pop_back, clear
  • [], at(), front/back, data()

4. Capacity

  • size(): number of elements
  • capacity(): allocated slot count
  • reserve(n): capacity ≥ n, size unchanged
  • resize(n): changes size
  • shrink_to_fit(): non-binding request to shrink capacity

5. Examples

erase-remove

vec.erase(std::remove(vec.begin(), vec.end(), value), vec.end());

sort + unique

std::sort(vec.begin(), vec.end());
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());

6. Common errors

  1. Out-of-range []
  2. erase + invalid iterator
  3. reserve mistaken for resize
  4. vector<bool> proxy quirks—consider vector<uint8_t> for bitwise buffers
  5. Signed/unsigned loop with size()

7. Performance

  • reserve when you know approximate final size
  • emplace_back for non-trivial types
  • const auto& in range-for
  • erase-remove instead of repeated erase in a loop

8. Best practices

  • Read-only parameters: const vector<T>&
  • Return large vectors by value (move/RVO in C++11+)
  • Don’t use data() across operations that reallocate

9. Production patterns

  • Reuse buffer: clear() keeps capacity for the next batch
  • Conditional reserve before insert/append ranges

10. Checklist

  • reserve for bulk inserts when size known
  • emplace_back for heavy types
  • Safe erase patterns
  • Avoid vector<bool> when you need pointers/refs to elements

FAQ

Is reserve too large bad?

A. It wastes memory but is safe; don’t reserve orders of magnitude more than you need.

emplace_back always?

A. Most valuable for non-trivial types; for int, similar to push_back.

vector vs array?

A. std::array<T,N>: fixed size at compile time; vector: runtime size.

One-line summary: Know size vs capacity, use reserve, and never trust [] for bounds without proof.

Next: vector/string performance

Keywords

C++, std::vector, STL, dynamic array, reserve, capacity, emplace_back, iterator

  • STL algorithms
  • Range-based for

References