* 잘못된 내용에 대한 피드백은 언제나 환영입니다. *
멍하
멍정이에요.
오늘은 STL컨테이너에 대해 정리해보아요.
STL 컨테이너란 무엇인가?
표준 라이브러리는 관련 개체 컬렉션을 저장할, 형식이 안전한 다양한 컨테이너를 제공합니다. 컨테이너는 클래스 템플릿입니다. 컨테이너 변수를 선언할 때 컨테이너가 보유할 요소의 형식을 지정합니다. 컨테이너는 이니셜라이저 목록을 사용하여 생성할 수 있습니다. 요소를 추가 및 제거하고 다른 작업을 수행하기 위한 멤버 함수가 있습니다.
https://learn.microsoft.com/ko-kr/cpp/standard-library/stl-containers?view=msvc-170
C++ 표준 라이브러리 컨테이너
자세한 정보: C++ 표준 라이브러리 컨테이너
learn.microsoft.com
간단하게 생각하면 list, queue 등의 자료구조를 제공한다고 생각하면 될 것 같아요.
컨테이너는 시퀀스 컨테이너, 연관 컨테이너, 컨테이너 어뎁터
이렇게 3가지로 나눌 수 있습니다.
시퀀스 컨테이너부터 천천히 알아보아요.

시퀀스 컨테이너(Sequence Container)
시퀀스 컨테이너는 지정된 요소가 삽이된 순서를 유지합니다. = 데이터를 순서대로 저장합니다.
순서를 유지하는 자료구조라고 할 수 있습니다.
vector container
배열과 비슷하게 사용할 수 있습니다. 필요에 따라 자동적으로 크기가 증가합니다. (= 동적 배열)
임의로 접근 가능하고(= 원하는 위치에서 꺼낼 수 있음), 길이가 매우 유연(= 길이를 직접 설정할 필요가 없음)합니다.
- heap에 저장
자주 쓰는 vector 멤버 함수
push_back(val) | 끝에 val 추가 | v.push_back(10); |
pop_back() | 마지막 요소 제거 | v.pop_back(); |
insert(pos, val) | pos 위치에 val 삽입 | v.insert(v.begin() + 1, 20); |
erase(pos) | pos 위치 요소 제거 | v.erase(v.begin() + 2); |
clear() | 모든 요소 삭제 | v.clear(); |
size() | 요소 개수 | v.size(); |
empty() | 비어있는지 확인 (비었으면 true) | if (v.empty()) |
front() | 첫 번째 요소 반환 | v.front(); |
back() | 마지막 요소 반환 | v.back(); |
at(i) | i번째 요소 (범위 검사 O) | v.at(0); |
operator[] | i번째 요소 (범위 검사 X) | v[0]; |
begin() | 첫 요소 반복자 | auto it = v.begin(); |
end() | 마지막 요소 다음 반복자 | auto it = v.end(); |
resize(n) | 크기 조절 (늘리면 기본값으로 채움) | v.resize(5); |
assign(n, val) | 크기를 n으로 하고 전부 val로 설정 | v.assign(3, 7); // {7, 7, 7} |
swap(v2) | 다른 벡터와 내용 교환 | v.swap(v2); |
사용 예시
#include <iostream>
#include <vector>
int main() {
std::vector<int> v;
v.push_back(1); // {1}
v.push_back(2); // {1, 2}
v.push_back(3); // {1, 2, 3}
v.insert(v.begin() + 1, 99); // {1, 99, 2, 3}
v.erase(v.begin()); // {99, 2, 3}
v.pop_back(); // {99, 2}
std::cout << "앞: " << v.front() << ", 뒤: " << v.back() << "\n"; // 앞: 99, 뒤: 2
v.resize(5); // {99, 2, 0, 0, 0} ← 기본값 0으로 채워짐
v.clear(); // {}
if (v.empty()) {
std::cout << "비었어요!\n";
}
}
array container
컴파일 시 크기가 고정됩니다.
- stack에 저장
at(i) | i번째 요소 반환 (범위 검사 O) | arr.at(2); |
operator[] | i번째 요소 (범위 검사 X) | arr[2]; |
front() | 첫 번째 요소 반환 | arr.front(); |
back() | 마지막 요소 반환 | arr.back(); |
data() | 내부 배열의 포인터 반환 | int* ptr = arr.data(); |
size() | 전체 요소 개수 반환 | arr.size(); |
fill(val) | 모든 요소를 val로 초기화 | arr.fill(0); |
begin() / end() | 반복자 반환 | std::sort(arr.begin(), arr.end()); |
swap(other) | 두 array 내용 교환 | arr1.swap(arr2); |
사용 예시
#include <iostream>
#include <array>
#include <algorithm>
int main() {
std::array<int, 5> arr = {3, 1, 4, 1, 5};
std::cout << "첫 번째: " << arr.front() << "\n"; // 3
std::cout << "마지막: " << arr.back() << "\n"; // 5
std::cout << "세 번째: " << arr.at(2) << "\n"; // 4
std::sort(arr.begin(), arr.end()); // 배열 정렬
std::cout << "정렬 후: ";
for (int x : arr) {
std::cout << x << " ";
}
std::cout << "\n";
}
deque(Double Ended Queue) container
이름 그대로 앞, 뒤에서의 삽입과 삭제를 빠르게 가능합니다. 연속된 메모리에 값을 저장하는 vector와 다르게 분산되어 여러 개의 메모리 블록으로 구성되어 있습니다. vector와 동일하게 크기를 동적으로 조절할 수 있습니다.
- heap에 저장
자주 쓰는 array 멤버 함수
push_back(val) | 뒤에 val 추가 | dq.push_back(10); |
push_front(val) | 앞에 val 추가 | dq.push_front(20); |
pop_back() | 뒤에서 요소 제거 | dq.pop_back(); |
pop_front() | 앞에서 요소 제거 | dq.pop_front(); |
front() | 앞 요소 반환 | dq.front(); |
back() | 뒤 요소 반환 | dq.back(); |
at(i) | i번째 요소 (범위 검사 O) | dq.at(1); |
operator[] | i번째 요소 (범위 검사 X) | dq[1]; |
size() | 요소 개수 | dq.size(); |
clear() | 전체 요소 제거 | dq.clear(); |
insert(pos, val) | 특정 위치에 삽입 | dq.insert(dq.begin()+2, 50); |
erase(pos) | 특정 위치 제거 | dq.erase(dq.begin()+1); |
begin() / end() | 반복자 | std::sort(dq.begin(), dq.end()); |
사용 예시
#include <iostream>
#include <deque>
int main() {
std::deque<int> dq;
dq.push_back(1); // {1}
dq.push_front(2); // {2, 1}
dq.push_back(3); // {2, 1, 3}
std::cout << "앞: " << dq.front() << "\n"; // 2
std::cout << "뒤: " << dq.back() << "\n"; // 3
dq.pop_front(); // {1, 3}
dq.pop_back(); // {1}
dq.push_back(4); // {1, 4}
dq.insert(dq.begin() + 1, 9); // {1, 9, 4}
for (int x : dq) {
std::cout << x << " ";
}
std::cout << "\n"; // 출력: 1 9 4
}
vector vs deque
항목 | vector | deque |
메모리 구조 | 연속된 메모리 블록 | 불연속적인 블록 (블록 단위로 나눠 저장) |
임의 접근 ([ ]) | 매우 빠름 (캐시 친화적) | 빠름 (하지만 vector보단 살짝 느림) |
뒤 삽입/삭제 (push_back/pop_back) | 매우 빠름 | 매우 빠름 |
앞 삽입/삭제 (push_front/pop_front) | 매우 느림 (모든 요소 이동 필요) | 빠름 (구조상 효율적) |
중간 삽입/삭제 | 느림 (이동 발생) | 비슷하게 느림 |
메모리 재할당 | 크기 늘어날 때 전체 복사 발생 | 블록 단위라 더 유연 |
캐시 효율성 | 좋음 (연속 메모리) | 약간 낮음 |
-> vector랑 deque는 거의 비슷하기 때문에 무난하게 vector도 괜찮지만 앞 뒤 삽입이 많은 구조라면 deque도 좋습니다.
list container
이중 연결 리스트의 형태로 양방향에서 빠르게 접근할 수 있지만, at, [ ]등의 임의 접근은 불가능합니다.
- heap에 저장
자주 쓰는 list 멤버 함수
push_back(val) | 뒤에 추가 | lst.push_back(10); |
push_front(val) | 앞에 추가 | lst.push_front(5); |
pop_back() | 뒤에서 제거 | lst.pop_back(); |
pop_front() | 앞에서 제거 | lst.pop_front(); |
insert(pos, val) | 위치에 삽입 | lst.insert(it, 3); |
erase(pos) | 위치 제거 | lst.erase(it); |
remove(val) | 해당 값 전부 제거 | lst.remove(10); |
clear() | 전체 삭제 | lst.clear(); |
size() | 요소 개수 | lst.size(); |
empty() | 비어 있는지 | lst.empty(); |
front() / back() | 첫/마지막 요소 반환 | lst.front(); |
begin() / end() | 반복자 반환 | auto it = lst.begin(); |
sort() | 정렬 | lst.sort(); |
unique() | 중복 제거 (연속된 값만) | lst.unique(); |
merge(other) | 정렬된 리스트끼리 병합 | lst.merge(lst2); |
reverse() | 순서 뒤집기 | lst.reverse(); |
사용 예시
#include <iostream>
#include <list>
int main() {
std::list<int> lst = {3, 1, 4, 1, 5};
lst.push_front(9); // 앞에 추가
lst.push_back(2); // 뒤에 추가
lst.sort(); // 정렬
lst.unique(); // 중복 제거 (연속된 것만)
for (int x : lst) {
std::cout << x << " ";
}
std::cout << "\n";
}
forward_list container
단일 연결 리스트의 형태로 한 방향으로만 연결되어 메모리 효율이 좋습니다.
- heap에 저장
자주 쓰는 forward_list 멤버 함수
push_front(val) | 앞에 요소 추가 | fl.push_front(10); |
pop_front() | 앞 요소 제거 | fl.pop_front(); |
insert_after(pos, val) | 특정 위치 다음에 삽입 | fl.insert_after(it, 5); |
erase_after(pos) | 특정 위치 다음 요소 삭제 | fl.erase_after(it); |
front() | 첫 번째 요소 반환 | fl.front(); |
clear() | 전체 삭제 | fl.clear(); |
empty() | 비어있는지 확인 | fl.empty(); |
before_begin() | 맨 앞 전 위치 반환 (삽입용) | fl.insert_after(fl.before_begin(), 1); |
begin() / end() | 반복자 반환 | for (auto it = fl.begin(); it != fl.end(); ++it) |
sort() | 정렬 | fl.sort(); |
unique() | 연속된 중복 제거 | fl.unique(); |
remove(val) | 특정 값 제거 | fl.remove(3); |
reverse() | 뒤집기 | fl.reverse(); |
merge(other) | 정렬된 리스트 병합 | fl.merge(other); |
사용 예시
#include <iostream>
#include <forward_list>
int main() {
std::forward_list<int> fl = {3, 1, 4, 1, 5};
fl.push_front(9); // {9, 3, 1, 4, 1, 5}
fl.sort(); // {1, 1, 3, 4, 5, 9}
fl.unique(); // {1, 3, 4, 5, 9}
fl.remove(4); // {1, 3, 5, 9}
fl.reverse(); // {9, 5, 3, 1}
for (int x : fl) {
std::cout << x << " ";
}
std::cout << "\n";
}
시퀀스 컨테이너 공통 함수
empty() | 비어 있는지 확인 (true / false) | 모든 컨테이너 공통 |
size() | 요소 개수 반환 | forward_list는 상대적으로 느림 |
front() | 첫 번째 요소 반환 | 없음 → 예외 발생 위험 있음 |
back() | 마지막 요소 반환 | forward_list는 ❌ 없음 |
clear() | 모든 요소 삭제 | 공통 |
begin() / end() | 반복자 반환 (for-each 가능) | 공통 |
insert(pos, val) | pos 위치에 삽입 | forward_list는 insert_after() |
erase(pos) | pos 위치 요소 삭제 | forward_list는 erase_after() |
'아무튼 공부중 > C++' 카테고리의 다른 글
[c++] std container2. 연관 컨테이너(Associative Container) (0) | 2025.04.04 |
---|---|
[c++] iostream(cout, cin)과 escape sequence (0) | 2025.03.18 |