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.
Related
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.
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.
i erase elements from middle of my deque frequently. memory address of elements in deque are used in some other places. does erasing middle element from deque invalided all pointers to deque like it does with vectors? should i switch to list?(i iterate whole deque anyways)
i tried to read deque implementation but it is complex, i don't understand if it acts as a list or vector.
I'm using visualc++ std implementation of deque.
Yes. An insertion in the middle invalidates all iterators and references to elements (and thus pointers to elements). An insertion at either end invalidates all iterators, but not references or pointers. And you don't read the implementation to find out such things; you read the documentation. (The implementation may actually allow operations which aren't officially supported. Until the next bug fix.)
does erasing middle element from deque invalided all pointers to deque like it does with vectors?
In case of a deque all iterators and references to the deque are invalidated, unless the erased members are at an end (front or back) of the deque.
For a vector all iterators and references before the point of insertion are unaffected, unless the new container size is greater than the previous capacity.
I would like to track a pointer to a list element for the next read access. This pointer would be advanced every time the list is read. Would it be bad practice to cache an iterator to the list as a member variable, assuming I take proper precautions when deleting list elements?
An iterator to a list element remains valid until the element it refers to is removed. This is guaranteed by the standard.
There is no problem with caching an iterator as long as you make sure you don't remove elements from the list or refresh the cached iterator when you do.
Iterators are meant to be used. They aren't just for looping over each element in a for-loop. All you have to take into account is the rules for iterator invalidation.
std::vector iterators can be invalidated by any operation that inserts elements into the list. The iterators for all elements beyond the point of insertion are invalidated, and all iterators are invalidated if the insertion operation causes an increase in capacity. An operation that removes an element from the vector will invalidate any iterator after the point of removal.
std::deque iterators are invalidated by any operation that adds or removes elements from anywhere in the deque. So it's probably not a good idea to keep these around very long.
std::list, std::set, and std::map iterators are only invalidated by the specific removal of the particular element that the iterator refers to. These are the longest-lived of the iterator types.
As long as you keep these rules in mind, feel free to store these iterators all you want. It certainly isn't bad form to store std::list iterators, as long as you can be sure that that particular element isn't going anywhere.
The only way you're going to be able to properly advance though an STL std::list<T> in a platform and compiler independent way is through the use of a std::list<T>::iterator or std::list<T>::const_iterator, so that's really your only option unless you're planning on implementing your own linked-list. Per the standard, as others here have posted, an iterator to a std::list element will remain valid until that element is removed from the list.