2016-07-25 3 views
0

나는 다음과 같다 std::map 여러 유형의 데이터 컨테이너를 사용하고 있습니다 :std :: map에서 일부 요소를 반복하여 지우는 동안 세그먼트 화 오류가 발생합니까?

std::map<int, std::vector<cv::Point> > mapGoodContours; 
    std::map<int, EllipseProperties> ellipsePropertiesMap; 
    std::map<int, float> m_markerRadiusMap; 
    std::map<int,cv::Point2f> markers;//This is part of another class 

나는 이러한 컨테이너를 통해 반복하고 다음 코드와 같이 이러한 요소가 특정 조건을 충족 한 후 일부 요소를 삭제.

auto radiusMapCounter = m_markerRadiusMap.begin(); 
    auto markerCounter = frames.markers.begin(); 
    auto goodContoursCounter = mapGoodContours.begin(); 

    if(m_markerRadiusMap.size()==ellipsePropertiesMap.size() && frames.markers.size()==ellipsePropertiesMap.size() 
      && mapGoodContours.size()==ellipsePropertiesMap.size()) 
    { 
     for(auto ellipsePropertyCounter = ellipsePropertiesMap.begin(); ellipsePropertyCounter != ellipsePropertiesMap.end(); ellipsePropertyCounter++) 
     { 

      float upperLimit = (float)m_upperFactor*(float)ellipsePropertyCounter->second.radius; 
      float lowerLimit = (float)m_lowerFactor*(float)ellipsePropertyCounter->second.radius; 
      if(ellipsePropertyCounter->second.minDistanceFromOtherEllipse>upperLimit 
         || ellipsePropertyCounter->second.minDistanceFromOtherEllipse<lowerLimit) 
      { 
       ellipsePropertiesMap.erase(ellipsePropertyCounter); 
       m_markerRadiusMap.erase(radiusMapCounter); 
       frames.markers.erase(markerCounter); 
       mapGoodContours.erase(goodContoursCounter); 
      } 
      else 
      { 
       smallContours.push_back(goodContoursCounter->second); 
      } 

      radiusMapCounter++; 
      markerCounter++; 
      goodContoursCounter++; 
     } 
    } 

가끔 이미지에 표시된대로 세그먼트 결함이 있음을 알기가 쉽지 않습니다. enter image description here 결함은 코드가있는 행을 가리 킵니다. radiusMapCounter++;

무엇이 잘못 되었나요?

+2

[반복기 무효화 규칙] 가능한 중복 (http://stackoverflow.com/questions/6438086/iterator-invalidation-rules) – MikeCAT

답변

3

컨테이너에서 가리키는 요소를 지운 후에 iterator를 증가시킬 수 없습니다. iterator의 사본을 만들고, 그것을 증가시키고, copy를 통해 요소를 삭제하십시오.

C++ 11 이상을 사용하는 경우 std::map::erase(...)은 마지막으로 제거 된 요소 다음에 반복기를 반환하므로 유효하지 않은 요소를 증가시키는 대신 사용할 수 있습니다. 이 경우 erase에서 사용할 반복기 복사본을 만들 필요가 없습니다.

for(auto ellipsePropertyCounter = ellipsePropertiesMap.begin(); 
    ellipsePropertyCounter != ellipsePropertiesMap.end(); 
    /* do not increment iterator here */) 
{ 

    float upperLimit = (float)m_upperFactor*(float)ellipsePropertyCounter->second.radius; 
    float lowerLimit = (float)m_lowerFactor*(float)ellipsePropertyCounter->second.radius; 
    if(ellipsePropertyCounter->second.minDistanceFromOtherEllipse>upperLimit 
       || ellipsePropertyCounter->second.minDistanceFromOtherEllipse<lowerLimit) 
    { 
     ellipsePropertyCounter = ellipsePropertiesMap.erase(ellipsePropertyCounter); 
     radiusMapCounter = m_markerRadiusMap.erase(radiusMapCounter); 
     markerCounter = frames.markers.erase(markerCounter); 
     goodContoursCounter = mapGoodContours.erase(goodContoursCounter); 
    } 
    else 
    { 
     smallContours.push_back(goodContoursCounter->second); 

     radiusMapCounter++; 
     markerCounter++; 
     goodContoursCounter++; 
     ellipsePropertyCounter++; // increment loop iterator only in 'else' case 
    } 
} 
0

다음은 C++ 17 솔루션입니다.

template<class=void,std::size_t...Is> 
void indexer(std::index_sequence<Is>...) { 
    return [](auto&& f) { 
    using discard=int[]; 
    (void)discard{0,((
     f(std::integral_constant<std::size_t, Is>{}) 
    ),void(),0)...}; 
    }; 
} 
template<std::size_t N> 
void indexer() { 
    return indexer(std::make_index_sequence<N>{}); 
} 

이제 erase_if, SFINAE는 작업을 제한해야한다 : C++ 14과 생성과 사용의 시점에서 특수 목적 도우미없이 인라인 인덱스 팩 압축을 해제 할 수 있습니다 첫 번째 indexer

, (및 기타 노드 기반) 컨테이너 :

이렇게하면 둘 중 하나의 테스트를 기반으로 여러 컨테이너에서 지울 수 있습니다.

코드 테스트를 거치지 않았으므로 아마도 오타가 될 수 있습니다.