STL map을 순환문 내에서 삭제시키는 것은 참 위험한 듯 하네요...

complexz의 이미지

vector, list등도 마찬가지지만...
map을 예로 들면
순환시키면서 특정 원소를 삭제시킬 필요가 있을 경우 그 방법이 어려울 뿐 더러
잠재적인 버그의 가능성이 높더군요.
가령...map의 경우 아래와 같이 다소 복잡한 방법으로 원소의 삭제가 가능한데요...

it = tempMap.begin();
for(;it != tempMap.end(); ){
  if(조건을 만족할 경우){
    tempMap.erase(it++);
  }else{
    ++it
  }
}

위의 코드에서 tempMap.erase(it++) 다음에 또다른 원소를 삭제할 경우
실행중 에러가 날 가능성이 많습니다.
즉, 두번째로 삭제된원소가 현재 it가 가리키는 원소의 바로 다음 원소일 경우 it++은
삭제된 원소를 가르키기 때문에 다음 순환에서 에러가 발생하는 경우죠..
삭제하는 순서를 바꾸면 되지만,
이렇게 순서를 특정하는 코드는 별로 좋지 못한거 같군요..
다른분들은 어떻게 해결을 하시는지??

익명 사용자의 이미지

template
void map_erase_if(Map& m, F pred)
{
typename Map::iterator i = m.begin();
while ((i = std::find_if(i, m.end(), pred)) != m.end())
m.erase(i++);
}

이렇게 해결합니다.

익명 사용자의 이미지

template <typename Map, typename F>
void map_erase_if(Map& m, F pred)
{
    typename Map::iterator i = m.begin();
    while ((i = std::find_if(i, m.end(), pred)) != m.end())
        m.erase(i++);
}
익명 사용자의 이미지

잘 이해가 가지 않습니다. 누가 설명 좀...?

yielding의 이미지

아주 깔끔한 generic function 이네요. 간단히 설명하면 다음과 같습니다

1.template 인자
Map: 임의의 (key, value) 타입을 지는 std::map
P: Predicate 비교 함수 혹은 비교 함수 객체

2. typename Map::itegator i = m.begin()
map 객체의 첫번째 원소를 가르키는 iterator(포인터라고 생각하면 됨) 획득
c++11 표준에서는 auto i = m.begin();

3. while
주어진 조건을 만족하는 (key, value) pair가 map에 존재하는 동안

4. m.erase(it++)
발견된 (key, value) pair를 삭제 후 포인터를 이동(it++)

이정도 되겠습니다.

Life rushes on, we are distracted

shint의 이미지

//
질문하신것처럼 사용합니다.
multi map 일때. 그렇게 사용하니까 에러가 없던거 같습니다.

//
그냥 map의 경우에는 이렇게 사용합니다.

i = max_count;
while (i--)
{
    map.erase(i);
}

//

template <typename Map, typename F>
void map_erase_if(Map& m, F pred)
{
    typename Map::iterator i = m.begin();
    while ((i = std::find_if(i, m.end(), pred)) != m.end())
        m.erase(i++);
}

이건.
i = m시작.
i = i 부터 m끝까지. pred를 m이 끝이 아닐때까지. 찾기.
i에 해당하는 m삭제.

왜 굳이 저렇게 하는지 모르겠습니다.
i++ 하면. 다음이 나올텐데요. i부터 m끝까지 굳이 왜 반복해서 찾아야 하나요?

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

yielding의 이미지

아래 코드에 문제가 없습니다. map이나 set같은 associative container에서 erase를 호출하는 아주 전형적인 idiom이죠.

it = tempMap.begin();
for(;it != tempMap.end(); ){
  if(조건을 만족할 경우){
    tempMap.erase(it++);
  }else{
    ++it
  }
}

단지 나이들면 위의 if안의 it++, ++it를 헤깔리지 않고 코딩하는 것이 어렵다는 문제가 있을뿐입니다. 그런 면에서 map_erase_if 함수 아주 깔끔하게 잘 만든 것 같네요

Life rushes on, we are distracted

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.