본문 바로가기

진리는어디에

[C++] STL map의 요소 삭제시 주의 할 점

요즘들어 포스팅 하는 주기가 점점 길어 지고 있네요.
날씨는 점점 추워지고 솔로들이 더욱 살아 남기 힘들어지는 크리스마스가 다가 오고 있습니다.

저도 크리스마스 때 남들처럼 거리를 활보 하고 싶습니다만 겨울의 거리는 솔로에겐 냉정하지요.

올 크리스마스는 징검다리 휴가라, 크리스마스 이브에 휴가를 내면 4일을 연속으로 쉴 수 있군요. 하지만 어디 딱히 갈 곳도 없고 오라는 곳도 없으니, 저는 웹 서핑이나 하면서 블로그 포스팅이나 하렵니다. 

오늘은 stl의 map의 erase에 대해서 간략하게 알아 보겠습니다.
보통 다른 stl의 컨테이너들은 erase를 하는 것에 대해 별다른 신경을 쓰지 않아도 별 문제가 없지만 map이란 녀석은 다른 컨테이너들 처럼 다루면 성질을 부리며 런타임 오류를 내버리는 경우가 있습니다(어쩌면 아무런 오류도 내지 않고 묵묵히 자기 할 일을 할 수도 있습니다만...정상적인 반응은 아닙니다).

위에서 언급 했지만, map 컨테이너의 반복자가 참조하고 있는 원소가 삭제되는 경우 큰 위험성이 있습니다. 예를 들어 :

typedef std::map<std::string, float> StringFloatMap;
StringFloatMap coll;
StringFloatMap::iterator pos;

// ....

for(pos = coll.begin(); pos != coll.end(); pos++) {
    if(pos->second == value) {
        coll.erase(pos);  // 런타임 에러
    }
}

coll.erase(pos) 이후에 coll의 반복자인 pos는 무효화 됩니다.

해당 반복자는 erase에 의해 이미 지워진 요소를 가리키고 있으므로 ++연산자는 정의 되지 않은 결과를 불러 옵니다(위에서 정상적으로 동작 할 수 있다고도 했지요? 정의 되지 않은 결과라서 그런겁니다).


이런 무효화를 방지 하기 위해서는 erase를 호출하기 전에 미리 반복자를 복사하고 erase를 호출 하면 됩니다.

typedef std::map<std::string, float> StringFloatMap;
StringFloatMap coll;
StringFloatMap::iterator pos;

// ....

for(pos = coll.begin(); pos != coll.end();) {
    if(pos->second == value) {
        coll.erase(pos++);
    }
    else {
        ++pos;
    }
}

coll.erase(pos++)은 다음 원소를 참조하기 위해서 pos를 증가 시킵니다. 하지만 ++ 이라는 것은 내부적으로 복사 하고 증가를 하는 것이기 때문에 pos는 erase에 의해 제거된 원소를 참조 하지 않고, 복사된 것을 참조하게 되므로써 안전하게 증가 할 수 있습니다.

부록 1. 같이 읽으면 좋은 글

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!