简体   繁体   中英

STL Vector, Iterator and Insert (C++)

I have a method to which a vector's iterator is passed. In this method I'd like to add some elements into the vector, but I am not sure whether this is possible when having only the iterator

void GUIComponentText::AddAttributes(vector<GUIComponentAttribute*>::iterator begin, vector<GUIComponentAttribute*>::iterator end)
{
    for (vector<GUIComponentAttribute*>::iterator i = begin; i != end; ++i)
    {
        GUIComponentAttribute &attrib = *(*i);

        // Here are the GUIComponentAttribute objects analyzed - if an object of a 
        // special kind appears, I would like to add some elements to the vector
    }
}

Thanks Markus

In the code you show, this is not possible. Especially because you should not add/remove elements to/from a vector while you iterate over it.

This is a long standing design "issue" in the STL. Iterators do not allow the modification of the structure of the underlying sequence they are iterating over: ie you can modify (sometimes) the elements themselves, but you cannot add/remove elements. Though InputIterator and OutputIterator are a bit special in this regard... hum...

This is actually the cause of the erase/remove idiom:

vec.erase(std::remove_if(vec.begin(), vec.end(), predicate), vec.end());

So, no, sorry, there is no way to actually modify the vector.

However, as exposed above, you can perfectly use the remove_if algorithm and simply return the new end of the valid range... or you can ask for the whole vector to begin with.

As noted by Björn, modifying a sequence structure while iterating over it is error-prone.

First, you'll have to change the interface. Given two iterators, there's no way to get back to the container to which they refer; so if you want to modify the container, you'll have to pass a reference to it, ie:

void GUIComponentText::AddAttributes(
        std::vector<GUIComponentAttribute*>& attributes )
{
    for ( std::vector<GUIComponentAttribute*>::iter = attributes.begin();
            iter != attributes.end();
            ++ iter )
    {
        //  ...
    }
}

Having done that: insertion can invalidate iterators. So it depends on where you want to insert. If you want to insert at the current position: std::vector<>::insert of a single element returns an iterator to that element, which was inserted before your element, so you can assign it to your iterator, adjust (if necessary), and continue:

iter = attributes.insert(iter, newAttribute);
++ iter;   //  Return to where we were...

If you're appending ( push_back ), the problem is a bit more complex; you need to calculate the offset, then reconstruct the iterator:

size_t offset = iter - attributes.begin();
attributes.push_back( nweAttribute );
iter = attributes.begin() + offset;

In this case, it is probably simpler to iterate using a size_t and [] , rather than an iterator.

It is not possible to add elements into a vector whilst iterating over it. In addition, you most certainly cannot add one to a vector with just a pair of iterators- you'd need a pointer/reference to the whole vector object.

The best you could do is return a vector of new components to add by the the calling function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM