erase가 까다로운가?vector 내부에서 일어나는 일vector는 연속 메모리이므로 중간 원소를 지우면 뒤 원소들이 앞으로 당겨집니다.erase 직후 "기존 it를 계속 쓰는 코드"는 매우 위험합니다.삭제 시 메모리 이동 개념
삭제 전: [10][20][30][40][50]
^
it (20)
erase(it) 후:
[10][30][40][50]
^
반환된 새 it (30)
기존 it는 더 이상 신뢰 불가
for (auto it = v.begin(); it != v.end(); ++it) {
if (*it % 2 == 0)
v.erase(it); // 잘못됨! it 무효화 → 크래시/스킵
}
erase 직후 it가 무효화될 수 있는데, 루프가 자동으로 ++it를 수행합니다.잘못된 vs 올바른 erase 패턴
[ 잘못된 코드 ]
v = {2, 4, 6} 삭제 조건: 짝수
it → 2 삭제 → it 무효화!
++it (잘못) → 다음 위치 건너뛰거나 크래시
삭제 전: [2][4][6]
it→2 삭제: [4][6] it는?(무효)
++it 수행: ??? (정의되지 않은 동작)
[ 올바른 코드 ]
it = v.erase(it) ← erase가 반환하는 "다음 유효한 it"로 갱신!
삭제 전: [2][4][6] it→2
erase(it): [4][6] 반환값 = 4를 가리키는 새 it
it = 반환값 → 그 다음 ++it 또는 계속 조건 검사
for (auto it = v.begin(); it != v.end(); ) {
if (*it % 2 == 0)
it = v.erase(it); // 반환값으로 갱신
else
++it;
}
it = v.erase(it); (반환된 다음 위치 사용)++itvector 조건 삭제의 기본 정답 패턴입니다.erase-remove_if 관용구조건 기반으로 다수 삭제가 목적이면 아래 패턴이 간결하고 성능도 좋습니다.
v.erase(
remove_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; }),
v.end()
);
remove_if는 "남길 원소를 앞으로 모으고" 새 논리적 끝 이터레이터를 반환합니다.erase(new_end, v.end())로 실제 꼬리 구간을 제거합니다.erase보다 보통 효율적이며(대체로 O(N)), 코드 의도가 분명합니다.remove_if 사용 시 <algorithm> 헤더가 필요합니다.end() 반환과 마지막 요소 삭제erase가 end()를 반환할 수 있습니다.end()는 비교용 센티널이지 역참조/증가 대상이 아닙니다.아래처럼 range-for 순회 중 erase를 호출하면 내부 이터레이터와 충돌할 수 있습니다.
for (int x : v) {
if (x % 2 == 0) {
// v.erase(...); // 위험: range-for 내부 순회 상태와 충돌 가능
}
}
range-for는 내부적으로 이터레이터를 사용합니다.erase-remove_if(8-4)를 사용하세요.| 상황 | 권장 방식 |
|---|---|
| 순회 중 조건부 삭제 + 세밀 제어 필요 | for (it ... ) + it = erase(it) |
| 조건으로 대량 삭제 | erase(remove_if(...), end()) |
| 단일 위치 삭제 | v.erase(pos) 후 반환값 처리 |
vector에서는 중간 erase가 이터레이터 무효화를 일으키기 쉬운가?erase와 erase-remove_if의 차이를 성능/가독성 관점에서 설명할 수 있는가?erase가 end()를 반환할 수 있는 상황을 코드로 보여줄 수 있는가?