C++ std::vector 완벽 가이드
C++을 실무에서 다루다 보면 컨테이너 선택이 성능과 유지보수에 미치는 영향이 정말 크다는 걸 체감하게 됩니다.
그중에서도 std::vector는 사용 빈도가 매우 높은 컨테이너로, 상황에 따라 유연하게 쓰일 수 있는 강력한 도구입니다.
하지만 단순히 선언하고 push_back만 한다고 끝나는 게 아니죠. 할당 최적화, 메모리 관리, 반복자 사용 등 다양한 관점에서 정확히 이해하고 써야만 실수 없는 코드를 만들 수 있어요.
그래서 오늘은 실무에서 바로 쓸 수 있는 예제 중심의 std::vector 완벽 가이드를 준비했어요.
기본적인 사용법부터 고급 활용, 성능 최적화까지 차근차근 살펴보며 여러분의 C++ 코드에 확실한 무기를 하나 더 추가해보세요!
📋 목차
📌 std::vector 기본 사용법과 선언 방법
C++에서 동적 배열(dynamic array)을 다룰 때 가장 대표적으로 사용하는 컨테이너가 바로 std::vector입니다.
배열처럼 데이터를 순차적으로 저장하지만, 필요할 때마다 자동으로 크기를 늘릴 수 있는 유연성을 갖고 있어요.
따라서 프로그램 실행 중에 요소 개수가 유동적으로 변하는 경우라면 vector가 가장 적합한 선택이 됩니다.
예: 유저 입력값 수를 미리 알 수 없을 때, 동적으로 생성되는 데이터를 저장할 때, 반복문 내에서 리스트를 구성할 때 등
vector는 다음과 같은 장점을 제공합니다.
- 🔹원소 추가 및 삭제가 매우 쉬움 (push_back, erase)
- 🔹랜덤 접근(인덱스 접근)이 빠름 (arr[i]처럼 사용 가능)
- 🔹메모리 자동 관리 및 재할당 처리
vector의 기본적인 선언 방법은 다음과 같으며, 템플릿 기반으로 다양한 타입에 사용할 수 있어요.
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers; // 기본 선언
std::vector<int> scores = {90, 85, 100}; // 초기화와 함께 선언
return 0;
}
기본적인 메서드와 초기화 방식도 다양합니다.
- 🔹push_back(): 요소 추가
- 🔹size(): 요소 개수 확인
- 🔹clear(): 모든 요소 삭제
std::vector는 배열처럼 사용 가능하면서도 크기를 자유롭게 조절할 수 있어 초기 개발에는 매우 편리한 선택입니다.
💡 주요 멤버 함수 및 반복자 활용
vector는 반복자(iterator)와 함께 사용할 때 가장 큰 강점을 발휘합니다. 다양한 멤버 함수를 반복자와 함께 활용하면 더 유연한 코드가 됩니다.
std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
for (auto it = names.begin(); it != names.end(); ++it) {
std::cout << *it << std::endl;
}
또한 C++11 이후부터는 range-based for loop를 활용해 더 간결하게 반복이 가능합니다.
for (const auto& name : names) {
std::cout << name << std::endl;
}
기타 자주 사용하는 멤버 함수는 다음과 같습니다.
함수 | 설명 |
---|---|
empty() | 벡터가 비었는지 확인 |
front(), back() | 첫 번째, 마지막 요소 접근 |
insert(), erase() | 삽입 및 삭제 (특정 위치에) |
resize() | 벡터의 크기를 조절 |
🛠️ 기본 사용법 예제 (삽입, 삭제, 조회, 순회)
std::vector 처음 접하는 분들을 위해 가장 기본적인 조작 방법부터 차근차근 예제를 통해 설명드릴게요. 다음은 가장 많이 사용하는 사용법입니다:
- 🔹벡터 선언하기
- 🔹요소 추가하기
- 🔹특정 위치에 삽입하기
- 🔹요소 접근하기
- 🔹요소 삭제하기
- 🔹전체 반복 출력하기
- 🔹크기 확인 및 전체 초기화
1. 벡터 선언하기
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers; // 정수형 벡터 선언
std::vector<std::string> names; // 문자열 벡터 선언
}
std::vector<타입> 변수명;으로 선언할 수 있으며, 템플릿으로 다양한 타입을 사용할 수 있어요.
2. 요소 추가하기 - push_back()
std::vector<int> numbers;
numbers.push_back(10);
numbers.push_back(20);
numbers.push_back(30);
push_back()은 벡터의 맨 뒤에 새로운 요소를 추가합니다. 가장 기본이 되는 메서드예요.
3. 특정 위치에 삽입하기 - insert()
std::vector<int> numbers = {1, 2, 3};
numbers.insert(numbers.begin() + 1, 100); // 1번 인덱스에 100 삽입
insert()는 반복자를 통해 위치를 지정해야 해요. 첫 번째 위치는 begin(), 끝은 end()입니다.
4. 요소 접근하기 - [] 또는 at()
std::vector<int> numbers = {10, 20, 30};
std::cout << numbers[1] << std::endl; // 20
std::cout << numbers.at(2) << std::endl; // 30
[]는 빠르지만 범위 검사 안 함, at()은 예외 처리 포함이 특징이에요.
5. 요소 삭제하기 - pop_back(), erase()
std::vector<int> numbers = {10, 20, 30, 40};
numbers.pop_back(); // 맨 마지막 요소(40) 삭제
// 두 번째 요소(20) 삭제
numbers.erase(numbers.begin() + 1);
pop_back()은 뒤에서 하나만 삭제하고, erase()는 원하는 위치의 요소를 제거할 수 있어요.
6. 전체 반복 출력하기 - for 문 활용
std::vector<int> numbers = {1, 2, 3};
for (int i = 0; i < numbers.size(); ++i) {
std::cout << numbers[i] << std::endl;
}
// 범위 기반 for문 (C++11 이상)
for (int num : numbers) {
std::cout << num << std::endl;
}
vector는 배열처럼 순차 접근이 가능하고, 범위 기반 for문으로 더 간편하게 사용할 수도 있어요.
7. 크기 확인 및 전체 초기화
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::cout << "size: " << numbers.size() << std::endl;
numbers.clear(); // 모든 요소 삭제
size()는 현재 요소 개수를 반환하고, clear()는 모든 요소를 삭제합니다.
🔍 실무에서 자주 사용하는 패턴
실무에서는 단순한 push/pop뿐 아니라, 다양한 패턴이 사용됩니다. 그중 자주 보이는 몇 가지를 소개할게요.
// 1. vector를 2차원 배열처럼 사용
std::vector<std::vector<int>> matrix(3, std::vector<int>(4, 0));
// 2. 정렬 및 검색
std::vector<int> data = {5, 2, 9, 1};
std::sort(data.begin(), data.end());
bool found = std::binary_search(data.begin(), data.end(), 5);
// 3. 특정 조건 필터링 (C++11 이상)
data.erase(std::remove_if(data.begin(), data.end(), [](int x){ return x < 5; }), data.end());
이런 패턴은 알고 있으면 실무에서 더 적은 코드로 강력한 기능을 구현할 수 있어요.
앞으로 STL 알고리즘과 함께 vector를 어떻게 조합할지 고민해보는 것도 좋은 훈련이 될 거예요.
🚀 성능 최적화를 위한 팁
std::vector는 내부적으로 동적 배열을 사용하기 때문에, 사용 방식에 따라 불필요한 메모리 재할당이 발생할 수 있습니다. 이를 방지하기 위한 몇 가지 성능 팁을 소개할게요.
// 1. reserve()로 미리 공간 확보
std::vector<int> numbers;
numbers.reserve(1000); // 1000개의 공간을 미리 확보하여 재할당 최소화
// 2. shrink_to_fit()으로 메모리 정리
numbers.shrink_to_fit(); // 사용 후 남는 메모리 회수 요청
// 3. swap()을 이용한 벡터 정리 트릭
std::vector<int>().swap(numbers); // 메모리 완전 초기화
reserve()는 반복적으로 push_back()을 할 때 특히 성능에 큰 영향을 줍니다.
대규모 데이터를 다룰 경우 반드시 고려해야 할 함수이며, 성능 차이는 벤치마크에서 확연히 드러납니다.
📊 std::array, std::list와의 비교
같은 컨테이너라고 해서 모두 같은 용도로 쓰이는 건 아니죠.
std::vector는 동적 배열이지만, std::array와 std::list는 각각 정적 배열과 연결 리스트 구조로 작동합니다.
각 컨테이너의 특징을 비교해보면 아래와 같습니다.
컨테이너 | 특징 | 추천 용도 |
---|---|---|
std::vector | 동적 크기 조절, 랜덤 접근 빠름 | 일반적인 리스트 처리 |
std::array | 고정 크기, 컴파일 타임 안전성 | 크기가 고정된 배열 처리 |
std::list | 양방향 링크, 삽입/삭제 빠름 | 중간 삽입/삭제 빈번한 경우 |
목적에 맞는 컨테이너 선택이 성능과 유지보수성을 크게 향상시킨다는 점, 꼭 기억하세요!
🧩 사용 시 주의사항 체크리스트
- 🔹불필요한 복사 방지를 위해 emplace_back() 사용 고려
- 🔹at()은 예외 처리를 포함하므로 성능 민감 구간에선 주의
- 🔹erase() 사용 후 반복자 무효화 주의 필요
위 항목들은 std::vector를 안전하고 효율적으로 사용하기 위해 꼭 체크해야 할 부분이에요.
❓ 자주 묻는 질문 (FAQ)
vector와 배열은 어떤 차이가 있나요?
vector는 쓰레드 안전한가요?
push_back과 emplace_back의 차이는 무엇인가요?
capacity와 size의 차이는 뭔가요?
vector를 함수에 인자로 전달할 때는 참조로 넘겨야 하나요?
vector 안의 객체를 정렬하려면 어떻게 하나요?
sort(v.begin(), v.end(), [](auto& a, auto& b){ return a.id < b.id; });
C++에서 std::vector는 단순한 컨테이너 그 이상입니다.
유연한 크기 조절, 강력한 반복자 지원, STL 알고리즘과의 궁합까지 갖춘 vector는 실무에서 빼놓을 수 없는 도구예요.
이번 글을 통해 기본 문법뿐만 아니라 실제 현업에서 자주 쓰이는 패턴과 성능 최적화 기법까지 정리해보았습니다.
특히 reserve, emplace_back, erase 후 반복자 처리처럼 놓치기 쉬운 디테일은 실전에서 매우 중요한 포인트가 됩니다.
지금까지 설명한 내용을 바탕으로 여러분의 C++ 코드가 더욱 안정적이고 효율적으로 작동하길 바랍니다.
C++, vector, std::vector, C++ 컨테이너, 동적 배열, 반복자, 성능 최적화, STL, 자료구조, C++ 실무
'프로그래밍 > C++' 카테고리의 다른 글
실무에서 바로 활용하는 C++ std::set 완벽 가이드 (0) | 2025.04.13 |
---|---|
실무에서 바로 활용하는 C++ std::map 완벽 가이드 (0) | 2025.04.13 |
C++ Structured Exception Handling (구조화된 예외 처리) (0) | 2023.10.03 |
C++11 주요 업데이트 : std::tuple, Variadic Templates, std::bind, std::function (0) | 2023.10.03 |
C++11 주요 업데이트 : Deleted Functions, User-defined Literals, constexpr (0) | 2023.10.03 |
댓글