1

A number of posts I've read lately claim for(const auto &it : vec) is the same as using the longer iterator syntax for(std::vector<Type*>::const_iterator it = vec.begin(); it != vec.end(); it++). But, I came upon this post that says they're not the same.

Currently, I'm trying to erase an element in a for loop, after it is used, and wondering if there is any way to convert const auto &it : nodes to std::vector<txml::XMLElement*>::iterator?

Code in question:

std::vector<txml2::XMLElement *> nodes;
//...
for (const auto &it : nodes)
{
    //...       
   nodes.erase(it);
}

I pretty sure I could just rewrite std::vector<txml2::XMLElement*> as a const pointer, but would prefer not to since this code is just for debugging in the moment.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
ZeroPhase
  • 649
  • 4
  • 21

2 Answers2

4

You should not be attempting to convert the range declaration in your range based for loop to an iterator and then deleting it whilst iterating. Even adjusting iterators while iterating is dangerous, and you should instead rely on algorithms.

You should use the Erase-remove idom.
You can use it with remove_if.

It would look something like:

  nodes.erase( std::remove_if(nodes.begin(), nodes.end(), [](auto it){

    //decide if the element should be deleted
    return true || false;

  }), nodes.end() );

Currently in the technical specifications, is erase_if.
This is a cleaner version of the same behaviour shown above:

std::erase_if(nodes,[](auto it){

    //decide if the element should be deleted
    return true || false;
});
Trevor Hickey
  • 36,288
  • 32
  • 162
  • 271
  • Thanks, that was a huge help. Ended up eventually just using `set_difference` but that got me on the right path. – ZeroPhase Jun 01 '16 at 04:06
1

You don't get an iterator but a reference to the element. Unless you want to do a std::find with it, it's pretty hard to get an iterator out of it.

Vectors are nice, so you could increase a counter per element and do nodes.begin() + counter to get the iterator, but it'd sort of defeat the point.

Also erasing the iterator in the for loop will result in you iterating after the end of the vector, you can test this code:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    vector<int> v = {0,1,2,3,4,5,6};

    for (int x : v) {
        cout << x << endl;

        if (x == 2) {
            v.erase(v.begin() + 2);
        }
    }
    return 0;
}

If you want to use iterators, just do a loop with them, if in addition you want to erase one mid-loop you have to follow this answer:

for (auto it = res.begin() ; it != res.end(); ) {
  const auto &value = *it;

  if (condition) {
    it = res.erase(it);
  } else {
    ++it;
  }
}

Note that you don't need to specify the whole type of the iterator, auto works just as well.

Community
  • 1
  • 1
coyotte508
  • 9,175
  • 6
  • 44
  • 63