C++ - Vector iterator not incrementable error - c++

I have myVector with some values of the type Texture_Map which is just an int.
I'm not erasing anything... I just want to insert a value in each even iteration.
Something like:
If I have this vector [1,2,3,4,5]
And my Texture_Map::TEXTURE_FLIP is 99, then my final vector should be:
[99,1,99,2,99,3,99,4,99,5]
After the first insert() I get the "Vector iterator not incrementable problem" error.
The code:
myVector.push_back(Texture_Map::TEXTURE_INIT);
for(unsigned int i = 0 ; i < m_max_pieces-2; i++)
myVector.push_back((Texture_Map::TextureID)i);
std::random_shuffle(myVector.begin(), myVector.end());
std::vector<Texture_Map::TextureID>::iterator it = myVector.begin();
for (it=myVector.begin(); it<myVector.end(); it++)
{
myVector.insert(it,Texture_Map::TEXTURE_FLIP);
}
Thanks!

As part of the consequence of using insert on a vector is that it:
Causes reallocation if the new size() is greater than the old capacity(). If the new size() is greater than capacity(), all iterators and references are invalidated. Otherwise, only the iterators and references before the insertion point remain valid. The past-the-end iterator is also invalidated.
The issue you're seeing is that you're attempting to increment an iterator which is no longer valid - it's past the insertion point, so it's invalidated. The solution here is to take advantage of that fact that insert returns an iterator:
iterator insert( iterator pos, const T& value );
Specifically:
Return value
1-2) Iterator pointing to the inserted value
So you want:
for (it=myVector.begin(); it<myVector.end(); it++) {
// now it will point to TEXTURE_FLIP
it = myVector.insert(it,Texture_Map::TEXTURE_FLIP);
// now it will point back to the original element
++it;
}

Related

Inserting an element in given positions (more than one) of a vector

I am trying to add a certain value in loop to a given position of a certain vector. For example:
the value is 11 and hence local_index = 11
The vector of position I have in input is neigh = {5,7}
The starting vector is Col={0,1,2,3,4,5,6,7,8,9,10}
I want to have as output Col={0,1,2,3,4,5,11,6,7,11,8,9,10}. This is my first try:
vector<long> neigh = {5,7};
long local_index = 11;
auto pos_col = Col.begin();
for (const auto& elem: neigh) {
Col.insert(pos_col+elem,local_index);
I keep getting for the second value of neigh a segmentation fault. So my questions are:
Is this because the insert return a pointer that cannot be re-assigned?
If the answer to the first question is yes, how can I achieve my goal?
Per the vector::insert() documentation on cppreference.com:
Causes reallocation if the new size() is greater than the old capacity(). If the new size() is greater than capacity(), all iterators and references are invalidated. Otherwise, only the iterators and references before the insertion point remain valid. The past-the-end iterator is also invalidated.
Which means that, after your 1st call to insert(), your pos_col iterator is now invalid for subsequent calls to insert(), as it refers to an element before the insertion point.
Try using this instead:
auto pos_col = Col.begin();
for (const auto& elem: neigh) {
Col.insert(pos_col+elem,local_index);
pos_col = Col.begin();
}
Or simply:
Col.insert(Col.begin()+elem,local_index);

Erase function of the std::vector

I have a std::vector and an iterator that points to an element in the vector. My question is how can I delete an element from the vector and keep the iterator?
I've tried using a second iterator to find the specific element that I want to delete and after erasing it with the erase function, the first iterator becomes invalid.
I have a std::vector and an iterator that points to an element in the vector. My question is how can I delete an element from the vector and keep the iterator?
Please note that when an element is deleted, no iterator can point to it as it ceases to exist. So, to reference it's location normal practice is just use the returned iterator from the erase() method. This allows use of the insert() method which will put a value in the position of the previously erased object.
With one iterator, just use this:
auto loc_after = v.erase(iter); // since the element has been erased loc_after points to the position the erased element had
I've tried using a second iterator to find the specific element that I want to delete and after erasing it with the erase function, the first iterator becomes invalid.
In the case of two iterators the elements can be easily erased by erasing the physically last iterator first since the earlier iterator is not invalidated. This is encapsulated in a function. The returned iterator points to one past the position of the "first" iterator regardless of order between the first and second iterator.
#include <vector>
#include <iostream>
// This returns an iterator positioned after where first_iter was before being erased
// this allows the insert(pos, val) method to insert a value in the the location just prior to pos
std::vector<int>::iterator second_iterator_loc(std::vector<int>& v, std::vector<int>::iterator first_iter, std::vector<int>::iterator second_iter)
{
std::vector<int>::iterator iter;
if (first_iter < second_iter)
{
v.erase(second_iter);
iter = v.erase(first_iter);
}
else if (second_iter < first_iter)
{
auto dist = first_iter - second_iter;
v.erase(first_iter);
iter = v.erase(second_iter) + dist - 1;
}
else
{
;// handler in case both iterators point to the same object
}
return iter;
}
int main()
{
std::vector<int> v{ 1,2,3,4,5 };
std::vector<int> v2 = v;
std::vector<int>::iterator iter1 = v.begin() + 1; // points to 2 in v
std::vector<int>::iterator iter2 = v.begin() + 3; // points to 4 in v
std::vector<int>::iterator iter;
iter = second_iterator_loc(v, iter1, iter2);
v.insert(iter, 9); // inserts a 9 in the previous location of the "first" iterator (where "2" was)
for (auto x : v)
std::cout << x << '\n'; // prints: 1 9 4 5
v = v2;
iter1 = v.begin() + 3; // reverse iterator positions
iter2 = v.begin() + 1;
iter = second_iterator_loc(v, iter1, iter2);
v.insert(iter, 9); // inserts a 9 in the previous location of the "first" iterator (where "4" was)
for (auto x : v)
std::cout << x << '\n'; // prints: 1 3 9 5
}
My question is how can I delete an element from the vector and keep the iterator?
You can't using std::vector::iterator. The iterator will be invalidated by erasing the element.
But you could achieve this by writing your own iterator class that stores a pointer to the vector and an index.
std::vector::erase will invalidate all iterators at or after the erased element:
Invalidates iterators and references at or after the point of the
erase, including the end() iterator.
However, erase will return an iterator pointing to the element following the last removed element. Maybe that is enough to satisfy your use case?

Unordered map containing an Iterator to a Vector - Iterator not Dereferencable C++

I have an unordered map that stores a string as its key and an iterator to a spot in a vector as its data. Each element in the vector holds a string and an int (number of times the string appears). I have coded an increaseCount(std::string, int) function that is supposed to insert the new string into the unordered map, unless it is already within the container. If this is the case, the function should find the key in the unordered map, got to the corresponding location in the vector that the iterator points to, and add one to the int parameter of the vector element. However, when executing the second case, the error "Vector iterator not dereferencable" shows up. Here is what I have coded.
void ourTrends::increaseCount(std::string s, unsigned int amount){
// check to see if key is already in
if(wordStoreTable.find(s) == wordStoreTable.end()){
// add the element into the hash table
std::vector<std::pair<std::string, int>>::iterator it;
std::pair<std::string, std::vector<std::pair<std::string, int>>::iterator> word (s, it);
wordStoreTable.insert(word);
// add element to back of vector
std::pair<std::string, int> p1 (s, amount);
sortedVector.push_back(p1);
//std::swap(sortedVector.front(), sortedVector.back());
// set the iterator of the hash pair to the end of the current vector size
it = sortedVector.end();
--it;
wordStoreTable.find(s)->second = it;
isSorted = false;
} else{
int x = wordStoreTable.find(s)->second->second;
std::pair<std::string, int> p1 (s, x + amount);
sortedVector.erase(wordStoreTable.find(s)->second);
sortedVector.push_back(p1);
//std::swap(sortedVector.begin(), sortedVector.end());
std::vector<std::pair<std::string, int>>::iterator it = sortedVector.end();
--it;
wordStoreTable.find(s)->second = it;
std::cout << wordStoreTable.find(s)->first << std::endl;
}
}
I know that this means the iterator is pointing to an empty location in memory, but I cannot figure out where it loses track of its destination.
The reason this code doesn't work, is that vector::push_back invalidates the iterators, that is, an iterator you had for a vector of size 3, might not work if you make the vector larger by adding a new element. From cppreference: If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.
You certainly could reserve enough space for the vector ahead of time, so that iterators do not invalidate, but as a general rule, you're better off with using numerical indices.

Should not Erasing from stl::list like this go to infinite loop?

Should not this code get into an infinite loop?
list<int>val;
val.push_back(0);
list<int>::iterator iter,iterEnd;
iter = val.begin();
int i;
for (; iter != val.end(); )
{
i = *iter;
if(i==0)
{
val.erase(iter++);
}
else iter++;
}
Since it has only one value after doing the erase and then incrementing the iterator, should not the iterator exceed the value val.end() and then fall into an infinite loop? But When I run it, it runs just fine! Can anyone explain please? Thanks.
In your example the iter is actually incremented before std::list::erase call and
References and iterators to the erased elements are invalidated. Other references and iterators are not affected.(cppreference)
so when the deletion occurs, iter is already pointing to the next valid element.
Pseudocode equivalent to lst.erase(iter++);:
temp = iter
iter += 1
lst.erase(temp)
after doing the erase and then incrementing the iterator
That's where you're wrong. It increments the iterator first (since function arguments are evaluated before calling the function), then erases the old value of the iterator.
Using post-increment (rather than incrementing in a separate step, erase(iter); ++iter;) is necessary since erase invalidates any iterators to the erased element. By incrementing first, iter itself is not invalidated, only the copy returned by the pre-increment.

vector iterators incompatible while erase from vector

I have a map which elements are vectors.I have to delete from these vectors all elements which are equal to special number num
std::map<size_t,std::vector<size_t> > myMap;
for (std::map<size_t,std::vector<size_t> >::iterator itMap = myMap.begin();itMap != myMap.end();++itMap )
{
for (std::vector<size_t>::iterator itVec = itMap->second.begin();itVec != itMap->second.end();)
{
auto itNextVec = itVec;
++itNextVec;
if (*itVec == num)
{
itMap->second.erase(itVec );
}
itVec = itNextVec;
}
}
The code causes run-time exepssion .In VS - vector iterators incompatible.
Can someone point what is the cause for that?
Thanks
std::vector::erase returns an iterator to the next position of the list, and so when you do an erase you should make your iterator equal to the returned value.
The only thing that you have to consider is that the returned iterator could be the end so you should check for that.
What I personally like to do is is after doing in an erase and I get the next iterator position, I go back to the previous position of the returned iterator and than call a continue on the for loop
Example:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> myInt;
myInt.push_back(1);myInt.push_back(2);myInt.push_back(3);
for(auto iter = myInt.begin();
iter != myInt.end();
++iter)
{
if(*iter == 1)
{
iter = myInt.erase(iter);
if(iter != myInt.begin())
{
iter = std::prev(iter);
continue;
}
}
std::cout << *iter << std::endl;
}
}
But doing an erase inside of a iterator loop is frowned upon because it invalidates the old iterator and that could cause a lot of issues if you didn't plan for them.
erasing will invalidate the iterator
Iterator validity
Iterators, pointers and references pointing to position (or first) and beyond are
invalidated, with all iterators, pointers and references to elements before position (or
first) are guaranteed to keep referring to the same elements they were referring to
before the call.
You can't trivially erase an item from a collection while iterating over it. Think a little about it, your removing what itVec "points" to, after the removal itVec no longer "points" to an element, so it no longer have a "next" pointer.
If you check e.g. this reference, you will see that the erase function returns an iterator to the next element. Continue the loop with this one (without increasing it of course).
Consider either using a different collection class than vector or creating a new vector with the desired items removed rather than removing from existing vector.