C++ std::vector 컨테이너
개요
std::vector
는 C++ 표준 라이브러리에서 제공하는 동적 배열 컨테이너로, 연속된 메모리 공간에 요소를 저장합니다. 자동으로 메모리를 관리하고 크기를 동적으로 조정할 수 있어 가장 널리 사용되는 컨테이너 중 하나입니다. 임의 접근이 가능하고, 끝에서의 삽입/삭제가 효율적입니다.
C++ 버전별 주요 키워드 도입 시기
- C++98/03: 기본
std::vector
기능 도입 - C++11: 이동 생성자/대입 연산자,
emplace_back()
,shrink_to_fit()
- C++14: 일반화된 람다 캡처와 함께 사용 개선
- C++17: 구조적 바인딩과 함께 사용 개선,
emplace_back()
이 참조 반환 - C++20:
std::span
과의 호환성,std::ranges
지원
내용 설명
주요 특징
- 동적 배열: 연속된 메모리 공간에 요소 저장
- 자동 크기 조정: 필요에 따라 메모리를 자동으로 재할당
- 임의 접근: 인덱스를 통한 O(1) 시간 접근
- 끝에서의 효율적 연산:
push_back()
,pop_back()
은 분할 상환 O(1) 시간 - 중간 삽입/삭제: O(n) 시간이 소요됨
주요 멤버 함수
size()
: 요소 개수 반환capacity()
: 할당된 메모리 공간의 크기 반환empty()
: 컨테이너가 비었는지 확인push_back()
: 끝에 요소 추가pop_back()
: 마지막 요소 제거insert()
: 지정된 위치에 요소 삽입erase()
: 지정된 위치의 요소 제거clear()
: 모든 요소 제거reserve()
: 용량 미리 할당shrink_to_fit()
: 용량을 현재 크기에 맞춤
예제 코드
#include <cstdint>
#include <iostream>
#include <vector>
int main()
{
// 크기 0으로 벡터 생성
auto my_vec_empty = std::vector<std::int32_t>{};
// 초기값을 가진 벡터 생성 (크기 5)
auto my_vec = std::vector<std::int32_t>{1, 2, 3, 4, 5};
// C 스타일 for 루프로 요소 접근
std::cout << "\nC-Style Loop: \n";
for (std::size_t i = 0; i < my_vec.size(); i++)
{
std::cout << my_vec[i] << '\n';
}
// 범위 기반 for 루프 (읽기 전용)
std::cout << "\nC++ Ranged For Loop (read-only): \n";
for (const auto value : my_vec)
{
std::cout << value << '\n';
}
// 범위 기반 for 루프 (값 수정)
for (auto &value : my_vec)
{
value *= 2; // 모든 요소를 2배로
}
std::cout << "\nAfter doubling all values:\n";
for (const auto value : my_vec)
{
std::cout << value << '\n';
}
// 크기 3의 벡터를 0으로 초기화하여 생성
auto my_vec2 = std::vector<std::int32_t>(3, 0);
std::cout << "\nVector with 3 zeros: \n";
for (const auto value : my_vec2)
{
std::cout << value << '\n';
}
// 요소 추가 및 제거
auto my_vec3 = std::vector<std::int32_t>{};
my_vec3.push_back(10);
my_vec3.push_back(22);
std::cout << "\nAfter push_back(10) and push_back(22): \n";
for (const auto value : my_vec3)
{
std::cout << value << '\n';
}
my_vec3.pop_back();
std::cout << "\nAfter pop_back(): \n";
for (const auto value : my_vec3)
{
std::cout << value << '\n';
}
// 반복자 사용
auto it_begin = my_vec2.begin(); // 첫 번째 요소를 가리키는 반복자
auto it_end = my_vec2.end(); // 마지막 요소 다음을 가리키는 반복자
std::cout << "\nUsing Iterators: \n";
for (; it_begin != it_end; ++it_begin)
{
std::cout << *it_begin << '\n';
}
// 요소 삽입
my_vec2.insert(my_vec2.begin() + 1, 100);
std::cout << "\nAfter inserting 100 at index 1: \n";
for (const auto value : my_vec2)
{
std::cout << value << '\n';
}
return 0;
}
실행 결과
C-Style Loop:
1
2
3
4
5
C++ Ranged For Loop (read-only):
1
2
3
4
5
After doubling all values:
2
4
6
8
10
Vector with 3 zeros:
0
0
0
After push_back(10) and push_back(22):
10
22
After pop_back():
10
Using Iterators:
0
0
0
After inserting 100 at index 1:
0
100
0
0
활용팁
- 사전 할당: 많은 요소를 삽입할 계획이라면
reserve()
로 메모리를 미리 할당하면 재할당 오버헤드를 줄일 수 있습니다. - 요소 접근:
at()
은 범위 검사를 수행하지만,operator[]
는 범위 검사를 하지 않아 더 빠릅니다. - 반복자 무효화: 요소를 추가하거나 제거하면 반복자와 참조가 무효화될 수 있으니 주의가 필요합니다.
- 용량 관리:
shrink_to_fit()
을 사용하여 불필요한 메모리를 해제할 수 있지만, 재할당이 발생할 수 있습니다. - 임시 객체:
emplace_back()
을 사용하면 임시 객체 생성을 피할 수 있어 더 효율적입니다. - 데이터 연속성: 연속된 메모리 공간을 사용하므로 C 스타일 배열과의 호환성이 좋습니다.
- 크기 vs 용량:
size()
는 실제 요소 수를,capacity()
는 할당된 메모리 공간을 반환합니다. - 예외 안전: 대부분의 연산이 강력한 예외 안전성(strong exception safety)을 보장합니다.
'개발 > C++ (98,03,11,14,17,20,23)' 카테고리의 다른 글
Modern C++ : std::vector, emplace_back vs push_back (98, 11, 17) (0) | 2025.08.22 |
---|---|
Modern C++ : template, std::span (20) (0) | 2025.08.20 |
Modern C++ : perfect forwarding (11) (1) | 2025.08.19 |
Modern C++ : rvalue reference summary (11) (2) | 2025.08.18 |
Modern C++ : lvalue, rvalue, value category (98, 11) (2) | 2025.08.17 |
Modern C++ : rvalue reference (98, 11) (1) | 2025.08.16 |
Modern C++ : lvalue rvalue reference (98, 11) (2) | 2025.08.15 |
Modern C++ : dynamic heap memory allocation (98, 11, 14) (1) | 2025.08.14 |