1.7.4 반복자 무효화
지금까지 어떤 컨테이너든 원소 접근, 순회, 삽입, 삭제 등의 작업을 반복자를 사용하여 모두 같은 방식으로 처리한다는 점을 확인했습니다. 반복자는 메모리 주소를 가리키는 포인터를 이용하여 구현되었기 때문에 경우에 따라 컨테이너가 변경될 경우 제대로 동작하지 않을 수 있습니다. 그러므로 컨테이너가 변경되어 특정 노드 또는 원소의 메모리 주소가 바뀌면 사용하던 반복자가 무효화될 수 있고, 이 경우 예측할 수 없는 동작이 발생할 수 있습니다.
벡터에서 맨 뒤에 원소를 추가하는 vector::push_back() 함수를 예로 들어보겠습니다. 이 함수는 경우에 따라 새로 메모리 공간을 할당하고 기존의 모든 원소를 새 메모리 공간으로 복사하는 동작이 발생합니다. 이 경우 기존에 사용하던 모든 반복자와 포인터, 참조는 모두 무효화됩니다. 마찬가지로 vector::insert() 함수를 수행할 때 메모리 재할당이 필요한 경우라면, 이 경우에도 기존의 반복자, 포인터, 참조는 모두 사용하면 안 됩니다. vector::insert() 함수에서 메모리 재할당 없이 원소를 삽입하는 경우라면, 원소 삽입 위치 이후에 있는 원소를 모두 이동해야 하므로 이 위치를 가리키는 반복자는 모두 무효화됩니다.
벡터와 달리 연결 리스트에서는 삽입 또는 삭제 동작에서 원소를 이동할 필요가 없으므로 반복자가 무효화되지 않습니다. 즉, std::list 또는 std::forward_list에서 삽입 동작은 반복자의 유효성에 영향을 미치지 않습니다. 다만 특정 원소를 삭제하는 경우, 삭제되는 원소를 가리키던 반복자는 당연히 무효화되지만 나머지 원소를 가리키는 반복자는 그대로 사용할 수 있습니다. 다음은 다양한 연산이 반복자에 어떤 영향을 주는지 확인하기 위한 예제 코드입니다.
std::vector<int> vec = {1, 2, 3, 4, 5};
auto v_it4 = vec.begin() + 4; // v_it4는 vec[4] 원소를 가리킵니다.
vec.insert(vec.begin() + 2, 0); // v_it4 반복자는 무효화됩니다.