C++ iterators problem

前端 未结 3 1774
傲寒
傲寒 2021-01-20 15:15

I\'m working with iterators on C++ and I\'m having some trouble here. It says \"Debug Assertion Failed\" on expression (this->_Has_container()) on line interIterator++. Dist

相关标签:
3条回答
  • 2021-01-20 15:54

    I'll take the liberty to rewrite the code:

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

    Why ?

    • The first loop (externIterator) iterates over a full range of elements without ever modifying the range itself, it's what a for is for, this way you won't forget to increment (admittedly a for_each would be better, but the syntax can be awkward)
    • The second loop is tricky: simply speaking you're actually cutting the branch you're sitting on when you call erase, which requires jumping around (using the value returned). In this case the operation you want to accomplish (purging the list according to a certain criteria) is exactly what the remove-erase idiom is tailored for.

    Note that the code could be tidied up if we had true lambda support at our disposal. In C++0x we would write:

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

    As you can see, we don't see any iterator incrementing / dereferencing taking place any longer, it's all wrapped in dedicated algorithms which ensure that everything is handled appropriately.

    I'll grant you the syntax looks strange, but I guess it's because we are not used to it yet.

    0 讨论(0)
  • 2021-01-20 15:56

    vector's erase() returns a new iterator to the next element. All iterators to the erased element and to elements after it become invalidated. Your loop ignores this, however, and continues to use interIterator.

    Your code should look something like this:

    if (condition)
        interIterator = externIterator->erase(interIterator);
    else
        ++interIterator;  // (generally better practice to use pre-increment)
    
    0 讨论(0)
  • 2021-01-20 16:01

    You can't remove elements from a sequence container while iterating over it — at least not the way you are doing it — because calling erase invalidates the iterator. You should assign the return value from erase to the iterator and suppress the increment:

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

    Also, never use post-increment (i++) when pre-increment (++i) will do.

    0 讨论(0)
提交回复
热议问题