2016-07-25 8 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

[Iterator invalidation rules]の重複の可能性があります(http://stackoverflow.com/questions/6438086/iterator-invalidation-rules) – MikeCAT

答えて

3

iteratorがコンテナからポイントしている要素を消去した後は、反復子をインクリメントすることはできません。イテレータのコピーを作成し、インクリメントし、コピーを使用して要素を削除します。

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

、連想(そしておそらく他のノードベース)コンテナ上:

template<class Test, class...Maps> 
bool erase_if(Test&& test, Maps&&...maps) { 
    using std::begin; using std::end; 
    std::tuple< decltype(begin(maps))... > its; 
    std::tuple< decltype(begin(maps))... > ends; 
    auto m_tup = std::tie(maps...); 
    auto index = indexer<sizeof...(maps)>; 
    index(
    [&](auto i){ 
     std::get<i>(its) = begin(std::get<i>(m_tup)); 
     std::get<i>(ends) = end(std::get<i>(m_tup)); 
    } 
); 
    while (its != ends) { 
    auto deref_then_test = [&test](auto...its) { 
     return test((*its)...); 
    }; 
    if (std::apply(deref_then_test,its)) { 
     index(
     [&](auto i){ 
      std::get<i>(its) = std::get<i>(m_tup).erase(std::get<i>(its)); 
     } 
    ); 
    } else { 
     index(
     [&](auto i){++std::get<i>(its);} 
    ); 
    } 
    } 
} 

これは、あなたがそれらのいずれかに複数のコンテナからオフに基づいてテストを消去することができます。

コードはテストされていません。おそらくコンティニュアスの誤植です。

関連する問題