연관 컨테이너 선택: map, unordered_map, set의 사용 기준
15강. 연관 컨테이너 선택: map, unordered_map, set의 사용 기준
이번 강의에서 해결할 문제
unordered_map은 평균 상수 시간 조회라는 이유로 항상 map보다 빠르다고 오해하기 쉽습니다. 실제 선택에는 정렬된 순회 필요, 해시 품질, 메모리, 원소 수, 최악 시간과 키 타입 지원이 함께 들어갑니다.
학습 목표
먼저 알아야 할 핵심 개념
map은 키 순서를 유지하는 균형 트리 계열이며 조회·삽입이 일반적으로 로그 시간입니다. unordered_map은 해시 버킷을 사용해 평균 상수 시간 조회를 목표로 하지만 rehash, 해시 충돌과 메모리 비용이 있습니다. set은 값 자체가 유일한 키이고 정렬된 집합이 필요할 때 사용합니다.
왜 이 문제가 위험한가
키가 존재하는지 확인한 뒤 operator[]를 사용하면 존재하지 않는 키가 기본값으로 삽입될 수 있습니다. unordered_map의 rehash는 iterator를 무효화할 수 있고 순회 순서는 안정된 출력 계약이 아닙니다. 저장 파일이나 테스트 결과가 순서를 요구하면 명시적으로 정렬해야 합니다.
가장 작은 예제로 시작하기
#include <iostream>
#include <string>
#include <unordered_map>
#include <unordered_set>
struct Task { int id{}; std::string name; };
int main() {
std::unordered_map<int, Task> byId;
byId.emplace(10, Task{10, "build"});
byId.emplace(20, Task{20, "test"});
if (const auto it = byId.find(20); it != byId.end()) {
std::cout << it->second.name << '\n';
}
std::unordered_set<std::string> tags{"cpp", "debug"};
std::cout << std::boolalpha << (tags.count("cpp") == 1) << '\n';
}
코드 한 줄씩 이해하기
byId는 정수 ID에서 Task 값으로 빠르게 조회하는 인덱스입니다.emplace결과를 확인하면 중복 ID 삽입 실패를 처리할 수 있습니다.find는 없는 키를 새로 만들지 않습니다.- iterator가 end가 아닐 때만 값을 사용합니다.
- 태그 중복 제거에는 key-value 쌍이 필요 없는 set 계열이 맞습니다.
실행 결과와 메모리·동작 흐름
출력은 test, true입니다. 해시 버킷의 실제 순회 순서는 사용하지 않습니다. ID 조회 결과는 해당 컨테이너 변경과 rehash 규칙 안에서만 유효하며 장기 iterator로 보관하지 않습니다.
단계별 실습
흔한 실수와 해결 방법
언제 사용하고 언제 피할까
키 순서가 필요하면 map, 평균 조회 중심이고 좋은 해시가 있으면 unordered_map, 유일한 값 집합이면 set 계열을 고려합니다. 원소 수가 적고 순차 탐색이 충분한 경우 vector가 더 단순하고 빠를 수도 있습니다.
게임 개발 연결
Unreal의 TMap과 TSet은 표준 컨테이너와 API·무효화·할당 정책이 동일하다고 가정하면 안 됩니다. 개념적 역할은 비교하되 실제 엔진 코드에서는 해당 버전 컨테이너 계약과 해시 함수 규칙을 확인합니다.
이해 점검 질문 3개
- unordered_map이 평균 상수 시간이어도 항상 빠르지 않은 이유는 무엇인가요?
- 읽기 조회에서 operator[]가 예상하지 않은 상태 변경을 만드는 이유는 무엇인가요?
- 안정된 정렬 출력이 필요한데 unordered_map을 쓴다면 무엇을 추가해야 하나요?
핵심 요약
다음 강의 연결
16강. 알고리즘 라이브러리에서 컨테이너 순회를 의도 중심 연산으로 표현합니다.
연관 컨테이너 선택: map, unordered_map, set의 사용 기준 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.