삶의 공유
C++ 벡터의 capacity와 size 완전 이해하기 본문

📝 C++ 벡터의 capacity와 size 완전 이해하기
— 메모리 동작부터 성능 최적화까지, STL vector 내부 구조를 제대로 알아보자
C++ std::vector는 실무와 알고리즘 구현에서 가장 자주 사용되는 컨테이너입니다. 그러나 많은 초보자들이 벡터의 핵심 개념인 capacity(용량) 와 size(요소 개수) 의 차이를 제대로 이해하지 못한 채 사용하고 있어, 불필요한 성능 저하나 메모리 낭비로 이어지는 경우가 많습니다. 오늘은 이 두 개념을 예제로 하나씩 보여주며, 벡터가 실제로 메모리를 언제 할당하고 언제 늘리고 줄이는지 깊이 있게 설명해보겠습니다.
1. capacity와 size란 무엇인가?
벡터는 내부적으로 동적 배열(dynamic array) 을 사용하므로, 새로운 요소가 추가되면 내부 배열 크기를 늘리기 위한 메모리 재할당이 필요할 수 있습니다. 이때 재할당 비용을 줄이기 위해 벡터는 “현재 요소 개수(size)” 보다 더 큰 메모리 공간(capacity)을 미리 확보해두곤 합니다.
- size
→ 현재 벡터가 실제로 보관하고 있는 원소의 개수 - capacity
→ 현재 벡터가 재할당 없이 저장할 수 있는 원소의 최대 개수
즉, capacity는 실제 배열의 크기이고, size는 그 배열 중에서 실제로 사용 중인 칸의 개수입니다.
2. capacity와 size 변화를 코드로 확인해보자
아래 예제는 vector의 resize, push_back, shrink_to_fit, clear 등 다양한 연산을 통해 capacity와 size가 어떻게 변하는지 확인하는 코드입니다.
#include <iostream>
#include <vector>
void check(const std::vector<int>& v)
{
std::cout << "capacity: " << v.capacity()
<< ", size: " << v.size() << '\n';
}
int main()
{
std::vector v = { 1,2,3,4,5 };
v.resize(3);
check(v);
v.push_back(0);
v.shrink_to_fit();
check(v);
v.push_back(0);
check(v);
v.clear();
check(v);
}
2-1. resize(3) 의 동작
초기 상태:
- capacity = 5
- size = 5
그 다음,
실행 결과:
📌 왜 size만 줄고 capacity는 그대로일까?
resize(3)은 요소 개수를 줄이는 동작이며, 내부 메모리를 해제하지 않습니다.
즉, 메모리는 그대로 둔 채 “사용 중인 요소 개수(size)”만 조정하는 것입니다.
벡터가 이렇게 설계된 이유는 간단합니다:
불필요한 메모리 재할당을 줄여 성능을 지키기 위해서
size는 감소했지만 capacity는 유지되어 다음 push_back이 빠르게 수행됩니다.
2-2. push_back(0) 실행 후
resize(3) 이후 capacity는 5이므로, 하나의 push_back은 재할당 없이 매우 빠르게 수행됩니다.
이 단계에서는 capacity > size 이므로 새로운 메모리 할당은 일어나지 않습니다.
2-3. shrink_to_fit() 의 동작
실행 결과:
📌 shrink_to_fit은 실제 메모리를 줄이는 함수
shrink_to_fit()은 현재 size에 맞춰 capacity를 줄입니다.
C++ 표준에서는 shrink_to_fit이 “요청(request)” 이라고만 정의하고 있어, 꼭 메모리를 줄여야 한다고 강제하지 않지만 대부분의 구현에서는 실제 메모리 축소가 이루어집니다.
즉, size == capacity인 상태로 만들어 내부 메모리 낭비를 제거합니다.
2-4. shrink_to_fit 이후 push_back 수행
이제 capacity == size == 4 인 상태에서
을 호출하면,
- capacity == size 이므로 새로운 메모리 할당 필요
- 재할당 비용이 발생하기 때문에 느린 연산
- 대부분의 STL 구현에서는 capacity를 여유 있게 늘립니다
예: 4 → 6, 4 → 8 등 (구현마다 다름)
결과:
2-5. clear() 는 메모리를 비우지 않는다
v.clear();
결과:
- clear()는 size만 0으로 만들고
- 실제 메모리(capacity)는 건드리지 않습니다.
❗ 메모리도 함께 비우고 싶다면?
v.clear(); // or v.resize(0);
v.shrink_to_fit();
이렇게 하면 capacity도 실제로 0 또는 최소 상태로 줄어듭니다.
3. reserve와 생성자 초기화 비교
두 번째 예제에서는 세 가지 방식으로 벡터를 생성하여 capacity와 size가 어떻게 달라지는지 확인합니다.
std::vector<int> v1;
check(v1);
std::vector<int> v2(5);
check(v2);
std::vector<int> v3;
v3.reserve(5);
check(v3);
3-1. std::vector<int> v1;
- 아무 것도 없는 빈 벡터입니다.
3-2. std::vector<int> v2(5);
- 5개의 요소가 0으로 초기화된 벡터 생성
- size와 capacity 모두 5
3-3. v3.reserve(5);
reserve는 메모리를 미리 확보만 하는 함수입니다.
- 요소는 없음 (size = 0)
- 메모리만 5칸 확보 (capacity = 5)
reserve의 장점
미래에 push_back이 여러 번 발생할 것이 예상된다면,
개발자가 capacity를 미리 크게 잡아두면 성능이 크게 향상됩니다.
단점:
- 실제 데이터를 저장하지 않아도 메모리를 점유한다는 점에서 메모리 관점에서 손해가 될 수 있습니다.
📘 전체 핵심 요약
- size는 실제 저장된 요소 개수이고 capacity는 실제 확보한 메모리 크기이다.
- resize()는 size만 바꾸며, 내부 메모리는 해제하지 않는다.
- push_back()은 capacity가 충분하면 빠르고, capacity가 꽉 차 있으면 느리다.
- shrink_to_fit()은 실제 메모리를 size에 맞춰 줄인다.
- clear()는 size만 0으로 만들고 메모리를 해제하지 않는다.
- reserve()는 미래에 많은 push_back이 예상될 때 유용하다.
- 벡터의 메모리 정책을 이해하면 성능 최적화에 큰 도움을 얻을 수 있다.
'Programing언어 > C++' 카테고리의 다른 글
| 반복자(Iterator)부터 C++20 Ranges까지: 메모리 구조와 동작 원리 완벽 해부 (0) | 2025.11.30 |
|---|---|
| 배열(Array) vs 벡터(Vector), 도대체 무엇을 써야 할까? (feat. std::array) (0) | 2025.11.30 |
| C++ STL 핵심 파헤치기: vector, list, deque... 대체 언제, 무엇을 써야 할까? (0) | 2025.11.03 |
| C++ 상속에서의 복사 생성자와 대입 연산자 완전 정리 (0) | 2025.10.18 |
| C++에서 Shallow Copy와 Deep Copy 완벽 정리 — 복사의 진짜 차이를 이해하자 (0) | 2025.10.16 |
