19. 컨테이너 반복자/참조/포인터 무효화 규칙과 재할당·rehash
난이도 중 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C++
// 주제: 표준 컨테이너의 반복자/참조/포인터 무효화(invalidation) 규칙과 재할당·rehash.
//
// 같은 "원소를 가리키는 포인터"가 컨테이너에 원소를 더 넣은 뒤에도 유효한지는 컨테이너마다
// 다르다. vector·list·map·unordered_map 은 재할당·rehash·node 저장 방식이 서로 달라, 삽입 후
// 반복자/참조/포인터의 유효성이 각각 어떻게 되는지도 다르다.
//
// 이 프로그램은 각 컨테이너에서 원소의 주소를 정수로 붙잡아 두고, 원소를 더 넣은 뒤
// 같은 논리적 원소의 주소가 그대로인지(1) 바뀌었는지(0) 를 출력한다.
//
// 과제:
// 1) 이 프로그램의 정확한 표준출력을 예측하라(네 줄).
// 2) vector 의 두 값이 왜 "1 0" 인지(용량 내 추가 vs 용량 초과 재할당) 설명하라.
// 3) list/map 의 값이 왜 1 인지(node 안정성) 설명하라.
// 4) unordered_map 이 왜 1 인지 — rehash 가 "반복자"와 "원소 참조/포인터" 중 무엇을
// 무효화하는지 구분해 설명하라.
#include <cstdio>
#include <cstdint>
#include <vector>
#include <list>
#include <map>
#include <unordered_map>
int main() {
// (2) vector: 용량 내 추가 vs 용량 초과 재할당
std::vector<int> v; v.reserve(2);
uintptr_t vd1 = (uintptr_t)v.data();
v.push_back(1); v.push_back(2); // 용량(2) 이내
uintptr_t vd2 = (uintptr_t)v.data();
v.push_back(3); // 용량 초과 → 재할당
uintptr_t vd3 = (uintptr_t)v.data();
std::printf("vec: %d %d\n", (int)(vd1==vd2), (int)(vd2==vd3));
// (3) list: node 안정성
std::list<int> l; l.push_back(100);
uintptr_t la1 = (uintptr_t)&l.front();
for (int i = 0; i < 50; i++) l.push_back(i);
uintptr_t la2 = (uintptr_t)&l.front();
std::printf("list: %d\n", (int)(la1==la2));
// (3) map: node 안정성
std::map<int,int> m; m[7] = 1;
uintptr_t ma1 = (uintptr_t)&m.at(7);
for (int i = 0; i < 50; i++) m[i] = i;
uintptr_t ma2 = (uintptr_t)&m.at(7);
std::printf("map: %d\n", (int)(ma1==ma2));
// (4) unordered_map: rehash 후 원소 참조/포인터 유지
std::unordered_map<int,int> um; um.reserve(2); um[7] = 1;
uintptr_t ua1 = (uintptr_t)&um.at(7);
for (int i = 0; i < 50; i++) um[i] = i; // rehash 유발
uintptr_t ua2 = (uintptr_t)&um.at(7);
std::printf("umap: %d\n", (int)(ua1==ua2));
return 0;
} 내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.