본문 바로가기
프로그래밍/C++

실무에서 바로 활용하는 C++ std::vector 완벽 가이드

by 머니테크리더 2025. 4. 14.
반응형

C++ std::vector 완벽 가이드

 

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::arraystd::list는 각각 정적 배열과 연결 리스트 구조로 작동합니다.

각 컨테이너의 특징을 비교해보면 아래와 같습니다.

컨테이너 특징 추천 용도
std::vector 동적 크기 조절, 랜덤 접근 빠름 일반적인 리스트 처리
std::array 고정 크기, 컴파일 타임 안전성 크기가 고정된 배열 처리
std::list 양방향 링크, 삽입/삭제 빠름 중간 삽입/삭제 빈번한 경우

목적에 맞는 컨테이너 선택이 성능과 유지보수성을 크게 향상시킨다는 점, 꼭 기억하세요!

 

 

🧩 사용 시 주의사항 체크리스트

  • 🔹불필요한 복사 방지를 위해 emplace_back() 사용 고려
  • 🔹at()은 예외 처리를 포함하므로 성능 민감 구간에선 주의
  • 🔹erase() 사용 후 반복자 무효화 주의 필요

위 항목들은 std::vector를 안전하고 효율적으로 사용하기 위해 꼭 체크해야 할 부분이에요.


❓ 자주 묻는 질문 (FAQ)

vector와 배열은 어떤 차이가 있나요?
배열은 크기가 고정되어 있지만 vector는 동적으로 크기를 조절할 수 있습니다. 또한 다양한 멤버 함수와 반복자 사용이 가능하다는 점에서 더 유연해요.
vector는 쓰레드 안전한가요?
기본적으로 std::vector는 쓰레드 안전하지 않아요. 멀티스레드 환경에서 사용할 경우 외부에서 동기화를 처리해줘야 합니다.
push_back과 emplace_back의 차이는 무엇인가요?
push_back은 객체를 복사하거나 이동하여 저장하지만, emplace_back은 해당 위치에 직접 생성하므로 불필요한 복사를 줄일 수 있어요.
capacity와 size의 차이는 뭔가요?
size는 현재 저장된 요소의 개수이고, capacity는 내부적으로 할당된 전체 메모리 공간입니다. size가 capacity를 초과하면 재할당이 발생해요.
vector를 함수에 인자로 전달할 때는 참조로 넘겨야 하나요?
네, 복사를 피하고 성능을 위해서 보통 const reference로 전달하는 것이 좋아요. 예: void func(const std::vector<int>& v)
vector 안의 객체를 정렬하려면 어떻게 하나요?
std::sort() 함수와 함께 람다식을 사용해 원하는 기준으로 정렬할 수 있어요. 예: 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++ 실무

 

 

반응형

댓글