Looking through the C++ vector documents, pop_back() is a function that will not cause a reallocation of the vector's data. However, this only works for removing one member of the vector. I am trying to find a way to erase multiple members from the end of a vector. Originally I thought I would call pop_back() in a small for loop but I was wandering if there was a more convenient function that would do this for me?
Edit:
The Cplusplus vector erase() reference is not as clear as it should be as pointed out by juanchopanza. It is why I originally discarded using erase(). Erase afterall, works well.
Use vector::erase. It will not reallocate memory.
If your erased range does not extend to the end of the container, it WILL re-locate the end elements. That means the ending elements will be moved to their proper spot in memory which likely incurs a data copy. That is not the same as a re-allocation of the backing store. If your ending element is myVector.end(), no relocation will need to occur.
You can use member functions erase. The vector will not be reallocated because according to the C++ Standard, e.g. C++17 n4659 standard draft 26.3.11.5 [vector.modifiers] "vector modifiers":
iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
3 Effects: Invalidates iterators and references at or after the point of the erase.
The bold part of the quote means that the vector will not be reallocated.
Related
I'm new to C++ and want to avoid newbie performance pitfalls.
Can erasing elements from a vector possibly cause a memory reallocation?
I'm working on a function that will add elements to a vector, and possibly erase some elements in the same frame.
No, it does not. If it did, it would invalidate all iterators, but, as cppreference states, it only Invalidates iterators and references at or after the point of the erase, including the end() iterator.
C++03 Standard § 23.2.4.3/3 describes std::vector::erase(iterator position) and says specifically
Invalidates all the iterators and references after the point of the erase.
Is the iterator at the point of the erase not invalidated? Specifically if I have a vector with a single element and I copy begin() iterator into a local variable and then call
vec.erase(vec.begin())
Will that iterator I have in a local variable get invalidated or not?
Will the iterators be invalidated after the point of erasure or after and including the point of erasure?
I'd say that your example with erasing the only element in the vector shows that the iterator at the insertion point must be invalidated.
Anyway, in C++11, the wording has been changed (23.3.6.5/3):
Effects: Invalidates iterators and references at or after the point of the erase.
The complexity of vector::erase() says: Linear on the number of elements erased (destructions) plus the number of elements after the last element deleted (moving).
It seems to me that it is implemented as a lazy grow/shrink array. The iterator, a pointer to the data, when erased, the following data will copied into its place. And thus the iterator you keep, will point to some data else, provided that the data you erase is not the last one.
In fact, it may depend on implementation. Yet I think a lazy grow/shrink array is the best-fit implementation for vector::erase(). [Since it may depends on implementation, don't count on anything like invalidate...]
Is it possible that inserting and/or erasing elements can invalidate iterators to existing elements.
Thank you.
Yes. The documentation for boost::ptr_vector<T> states:
A ptr_vector<T> is a pointer container that uses an underlying std::vector<void*> to store the pointers.
And inserting elements into or erasing elements from a std::vector can cause re-allocation and therefore existing iterators to be invalidated.
Specifically, §23.3.6.5/3 of C++11 states about erase():
(3) Effects: Invalidates iterators and references at or after the point of the erase.
and about insert() and push_back():
(1) Remarks: Causes reallocation if the new size is greater than the old capacity. If no reallocation happens, all the iterators and references before the insertion point remain valid.
Therefore, to prevent iterator invalidation in the case of element insertion, you may use the reserve() function to increase the vector's capacity before obtaining any iterators from it. Those iterators will then remain valid until the size() of the vector exceeds the number of elements space was reserved for.
I seem to be having a problem displaying an item in a vector with an iterator. Possibly, I just need another set of eyes to look at it.
vector<string> tempVector;
vector<string>::iterator it;
it = tempVector.begin();
tempVector.push_back("1");
cout << *it;
I know this isn't the full code, but it's the only portion running. The output is a segfault. doesn't the iterator point to the beginning of the vector? I was expecting to get "1" to cout.
The call to vector::reserve() invalidates all existing iterators if it happens to require reallocation.
To quote the C++ standard, 23.3.6.3[vector.capacity]
Reallocation happens at this point if and only if the current capacity is less than the argument of reserve().
[...]
Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence.
EDIT: After the edit, you have a call to vector::push_back(), which also invalidates all iterators if it requires reallocation. Iterator invalidation rules may be helpful.
std::vector<string> names;
std::vector<string>::iterator start = names.begin();
std::vector<string>::iterator end = names.end();
sort (start,end);
//are my start and end valid at this point?
//or they do not point to front and tail resp?
According to the C++ Standard §23.1/11:
Unless otherwise specified (either explicitly or by defining a function in terms of other functions), invoking
a container member function or passing a container as an argument to a library function shall not invalidate
iterators to, or change the values of, objects within that container.
§25.3 "Sorting and related operations" doesn't specify that iterators will be invalidated, so iterators in the question should stay valid.
They still point to the beginning and end. The values in those slots of the vector have probably changed, but the storage location in which each resides remains the same.
std::sort will not invalidate iterators to a vector. The sort template uses the * operator on the iterators to access and modify the contents of the vector, and modifying a vector element though an iterator to an element already in the vector will not invalidate any iterators.
In summary,
your existing iterators will not be invalidated
however, the elements they point to may have been modified
In addition to the support for the standard provided by Kirill V. Lyadvinsky (Does a vector sort invalidate iterators?):
25/5 "Algorithms library"
If an algorithm’s Effects section says
that a value pointed to by any
iterator passed as an argument is
modified, then that algorithm has an
additional type requirement: The type
of that argument shall satisfy the
requirements of a mutable iterator
(24.1).
24.1/4 "Iterator requirements"
Besides its category, a forward,
bidirectional, or random access
iterator can also be mutable or
constant depending on whether the
result of the expression *i behaves as
a reference or as a reference to a
constant.
std::vector keeps its elements in contiguous memory. std::sort takes arguments (iterators) by value and re-arranges the sequence between them. The net result is your local variables start and end are still pointing to first and one-past-the-last elements of the vector.