빠른 비교
cpp
#include <map>
#include <unordered_map>
std::map<std::string, int> scores; // 정렬 순서 유지 (O(log n))
scores["Alice"] = 95;
scores["Bob"] = 88;
std::unordered_map<std::string, int> freq; // 해시, 빠름 (O(1) 평균)
for (const char c : text) ++freq[c];
// 안전한 조회 — find
auto it = scores.find("Charlie");
if (it != scores.end()) use(it->second);정렬 순서가 필요하면 map, 평균 조회 속도가 더 중요하면 unordered_map부터 봅니다. 조회할 때는 []가 삽입까지 한다는 점을 같이 기억해야 합니다.
갈리는 기준
먼저 다시 보는 기본형은 아래입니다.
- 정렬 보장 키-값 저장:
std::map - 해시 기반 평균 O(1) 조회:
std::unordered_map - 조회만 할 때:
find - 없으면 넣고 싶을 때:
[],try_emplace,insert_or_assign
어떤 연관 컨테이너를 먼저 고르면 되나
| 상황 | 먼저 떠올릴 것 |
|---|---|
| 키 정렬 순회가 필요함 | std::map |
| 평균 조회 속도가 더 중요함 | std::unordered_map |
| 읽기만 확인 | find 또는 contains |
| 없을 때만 생성 | try_emplace |
| 있으면 덮어쓰기 | insert_or_assign |
map vs unordered_map — 언제 무엇을 쓰나
map은 레드-블랙 트리로 키를 정렬 순서로 유지합니다. unordered_map은 해시 테이블로 평균 O(1) 접근을 제공하지만 정렬 순서는 없습니다.
cpp
std::map<std::string, int> m{{"b", 2}, {"a", 1}, {"c", 3}};
for (auto& [k, v] : m) std::cout << k; // "abc" — 항상 정렬됨
std::unordered_map<std::string, int> u{{"b", 2}, {"a", 1}, {"c", 3}};
for (auto& [k, v] : u) std::cout << k; // 순서 불정 — "bac" 또는 다른 순서[] vs find — 조회 방식의 차이
[] 연산자는 키가 없으면 기본값으로 자동 생성합니다. 의도치 않은 원소 삽입이 발생할 수 있습니다. find는 없으면 end()를 반환하고 원소를 생성하지 않습니다.
cpp
std::map<std::string, int> m;
// ❌ 없는 키 조회 시 0으로 자동 삽입
int val = m["missing"]; // m에 "missing": 0 삽입됨!
std::cout << m.size(); // 1
// ✅ 조회만 할 때는 find 사용
auto it = m.find("missing");
if (it != m.end()) use(it->second);
else std::cout << "키 없음";효율적인 삽입 — try_emplace · insert_or_assign
이미 존재하는 키는 건드리지 않고 삽입하려면 try_emplace, 항상 덮어쓰려면 insert_or_assign을 씁니다.
cpp
std::unordered_map<std::string, int> counts;
// insert_or_assign — 있으면 덮어씀, 없으면 삽입
counts.insert_or_assign("key", 10);
// try_emplace — 없을 때만 삽입, 있으면 아무것도 안 함
auto [it, inserted] = counts.try_emplace("key", 10);
if (inserted) std::cout << "새로 삽입";
else std::cout << "기존 값: " << it->second;cpp
// ❌ 값 생성 비용이 큰데 []로 먼저 기본 삽입
cache[key] = buildExpensiveValue();
// ✅ 없을 때만 생성
cache.try_emplace(key, buildExpensiveValue());선택 기준
- 정렬 순서 필요:
std::map - 평균 조회 성능 우선:
std::unordered_map - 조회만 확인:
find - 없으면 기본값 삽입:
[] - 없을 때만 삽입:
try_emplace - 항상 덮어쓰기:
insert_or_assign
주의할 점
const 맵에서 []를 쓰면 컴파일 오류입니다. 존재하지 않을 수 있는 키에는 at() 대신 find()를 쓰세요.
cpp
const std::map<std::string, int> m{{"a", 1}};
// ❌ const 맵에서 [] 사용 — 컴파일 오류
int v = m["a"];
// ❌ at()은 없는 키에서 std::out_of_range 예외
int v2 = m.at("b"); // 예외 발생
// ✅ find로 안전하게 조회
auto it = m.find("a");
if (it != m.end()) use(it->second);cpp
// ❌ 존재 여부만 확인하려고 []를 쓰면 원소가 늘어난다
if (counts["missing"] == 0) {
// 여기서 이미 "missing"이 삽입됨
}
// ✅ 읽기만 할 때는 find 또는 contains(C++20)
if (counts.find("missing") == counts.end()) {
// 삽입 없음
}참고 링크
2 sources