2016-07-25 70 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无效规则]的可能重复(http://stackoverflow.com/questions/6438086/iterator-invalidation-rules) – MikeCAT

回答

3

删除指向容器的元素后,不能递增迭代器。创建一个迭代器的副本,增加它,通过复制删除元素。

如果您使用的是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解决方案。

首先indexer,这是C++ 14,并允许您创建和使用点的在线解压指数包无特殊用途的助手:现在

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仅限于工作在联想(也许其他节点为基础的)容器:

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);} 
    ); 
    } 
    } 
} 

这可以让你从多个容器擦除其中的一个基于关测试。

代码没有测试,可能contians错别字。