C ++迭代器问题

时间:2010-04-28 10:18:57

标签: c++ iterator vector

我正在使用C ++上的迭代器,我在这里遇到了一些麻烦。它在行interIterator ++上的表达式(this-> _Has_container())上说“Debug Assertion Failed”。 距离列表是矢量<矢量< DistanceNode>取代。我做错了什么?

vector< vector<DistanceNode> >::iterator externIterator = distanceList.begin();

   while (externIterator != distanceList.end()) {

    vector<DistanceNode>::iterator interIterator = externIterator->begin();

        while (interIterator != externIterator->end()){

          if (interIterator->getReference() == tmp){

     //remove element pointed by interIterator
     externIterator->erase(interIterator);             

          } // if
    interIterator++;
  } // while
  externIterator++;
   } // while      

3 个答案:

答案 0 :(得分:13)

vector erase()向下一个元素返回一个新的迭代器。擦除元素之后的元素的所有迭代器都将失效。但是,您的循环忽略了这一点,并继续使用interIterator

您的代码应如下所示:

if (condition)
    interIterator = externIterator->erase(interIterator);
else
    ++interIterator;  // (generally better practice to use pre-increment)

答案 1 :(得分:5)

在迭代它时,你不能从序列容器中删除元素 - 至少不是你这样做的方式 - 因为调用erase使迭代器无效。您应该将erase的返回值赋给迭代器并抑制增量:

while (interIterator != externIterator->end()){
   if (interIterator->getReference() == tmp){
       interIterator = externIterator->erase(interIterator);             
   } else {
       ++interIterator;
   }
}

此外,在预增量(++ i)执行时,永远不要使用后增量(i ++)。

答案 2 :(得分:1)

我将冒昧地重写代码:

class ByReference: public std::unary_function<bool, DistanceNode>
{
public:
  explicit ByReference(const Reference& r): mReference(r) {}
  bool operator()(const DistanceNode& node) const
  {
    return node.getReference() == r;
  }
private:
  Reference mReference;
};

typedef std::vector< std::vector< DistanceNode > >::iterator iterator_t;

for (iterator_t it = dl.begin(), end = dl.end(); it != end; ++it)
{
  it->erase(
     std::remove_if(it->begin(), it->end(), ByReference(tmp)),
     it->end()
  );
}

为什么?

  • 第一个循环(externIterator)遍历整个范围的元素,而不会修改范围本身,这是for的用途,这样你就不会忘记增加(不可否认的是for_each会更好,但语法可能很尴尬)
  • 第二个循环很棘手:简单地说,当你打电话erase时,你实际上正在切割你所坐的分支,这需要跳转(使用返回的值)。在这种情况下,您要完成的操作(根据特定条件清除列表)正是为remove-erase惯用法定制的。

请注意,如果我们拥有真正的lambda支持,可以整理代码。在C ++ 0x中,我们会写:

std::for_each(distanceList.begin(), distanceList.end(),
  [const& tmp](std::vector<DistanceNode>& vec)
  {
    vec.erase(
      std::remove_if(vec.begin(), vec.end(),
        [const& tmp](const DistanceNode& dn) { return dn.getReference() == tmp; }
      ),
      vec.end()
    );
  }
);

正如您所看到的,我们看不到任何迭代器递增/解除引用,它们全部包含在专用算法中,以确保一切都得到妥善处理。

我会告诉你语法看起来很奇怪,但我想这是因为我们还没有习惯它。