Reallocating Iterators [REWRITTEN] - c++

How would you insert at a certain location in an STL vector?
So far, I have tried inserting into an STL vector like so:
someVector.insert(someVector.begin() + location, info);
This works when I'm inserting items in sequence, but when I delete an item from the vector, I want to be able to insert at that location. However, the iterator needs to be reallocated since it throws a "vector iterator + offset out of range" error. (I'm pretty new to C++ iterators, so I'm not entirely sure what "iterator reallocation" is and can't seem to find a good explanation, so if you can explain, please feel free!) I can find a lot of questions that ask when the iterator needs to be reallocated but not on the best way to do so. Alternatively, would there be a different/better way to insert at a position?

The erase operation on a vector returns the iterator one past the just-erased element. You can use that iterator as the subsequent insertion position to insert "at the place" where you erased:
auto it = v.begin() + 3; // say
it = v.erase(it); // erase and store position
v.insert(it, -3); // insert at that position

Related

why iterator doesnt get to end of vector?

I made a vector v which is [-5,-3]. I assigned an iterator iti to its beginning and then assigned another iterator itj as iti+1. Since my vector only has 2 elements, I would think that itj is recognized as the end of the vector or v.end(). But it is not.
Any ideas why that might be happening?
vector<int>v;
v.push_back(-5);
v.push_back(-3);
vector<int>::iterator iti, itj;
iti = v.begin();
itj = iti + 1;
if(itj==v.end())
cout << "1";
else
cout << "2";
Why does this print out '2' and not '1'?
end is an iterator to the (non-existing) element after the last element. iti + 2 would equal end because the vector has 2 elements. Generally, for a vector of size N: begin + N equals end.
The definition of vector:: end() is made in such a way that it returns the iterator which points to the (imaginary) element next to the last element.
Now, this might appear stupid initially, but is actually very useful, because, generally you use an iterator to iterate through a vector. And that is usually done using a for loop. So people do
for (vector<int>:: iterator i = v.begin();i!=v.end();i++)
which iterates over the whole vector.
Now I am not saying that we cannot achieve this if end returns an iterator to the last element. It is of course possible to do it, if we change the structure of our loop a little.
So, let us assume for a moment that end does return an iterator pointing to the last element. Now try to write a piece of code to iterate over the whole vector, say to print it. You will understand why the designers chose this kind of a convention. Remember that you cannot compare two iterators with <= like you do with normal integer indices.
BTW, it is the same convention for all STL containers.

Insert object at index of vector c++

I need to insert an object to existing vector of objects. I know that i need to use iterator to do it but i dont know how it exactly works.
I have alphabetically sorted vector and i need to insert new object by its name in exact index that i got after some search . So i have this.
vector<Person>people;
int index =54;
Person temp;
people.push_back(temp);//insert at end of vector
people.insert(index, temp);//doesnt work for int
Can anyone help me how to use iterator properly to insert my object to 54th index of vector and move all following object by one index ?
Thank you for any help.
The straight forward answer is you need an iterator. The iterator for std::vector supports random access, which means you can add or subtract an integer value to or from an iterator.
people.insert(people.begin() + index, temp);
The better answer is don't use an index, use an iterator. What is your loop? You should be able to refactor the loop to use an iterator instead of an index.
I have alphabetically sorted vector and i need to insert new object by its name in exact index that i got after some search.
If the vector is sorted alphabetically, then the proper way of inserting an item in the correct position while maintaining the sort order is using the upper_bound function:
people.insert(upper_bound(people.begin(), people.end(), temp), temp);
The function searches the sorted range, and returns the position of the first element that is greater than temp.
Here is a demo on ideone.
Solution:
vector<Person>::iterator iter = people.begin() + index;
people.insert(iter, temp);
Reference:
std::vector::insert()
RandomAccessIterator

c++ iterators double loops

I'm trying to do something like the following:
myvec is a vector of Couple objects (formed each with an EntityA and an EntityB).
I'm trying to remove the duplicate couples..
Anyway sometimes the following code crashes with an out of bound it2.
The condition is fine, the iterators seems not
if(myvec.size()>1)
for(vector<Couple>::iterator it1 = myvec.begin(); it1+1 !=myvec.end();){
for(vector<Couple>::iterator it2 = it1+1; it2 !=myvec.end();){
if((it1->EntityA!=it2->EntityA&&it1->EntityA!=it2->EntityB)||
(it1->EntityB!=it2->EntityA&&it1->EntityB!=it2->EntityB)){
it2++;
}
else{
myvec.erase(it2);
}
}
it1++;
}
Any solution/alternative?
Use the existing library functions whenever possible. You will need to provide a binary predicate function, or provide an operator< and operator== for your Couples object.
std::sort(myvec.begin(), myvec.end());
myvec.erase(std::unique(myvec.begin(), myvec.end()), myvec.end());
However, it may be better for you to have a container that will automatically avoid duplicates like std::set. This is a related question, with an excellent answer.
if(myvec.size()>1)
for(vector<Couple>::iterator it1 = myvec.begin(); it1+1 !=myvec.end();){
for(vector<Couple>::iterator it2 = it1+1; it2 !=myvec.end();){
if((it1->EntityA!=it2->EntityA&&it1->EntityA!=it2->EntityB)||
(it1->EntityB!=it2->EntityA&&it1->EntityB!=it2->EntityB)){
it2++;
}
else{
it2 = myvec.erase(it2);
}
}
it1++;
}
Return value A random access iterator pointing to the new location of
the element that followed the last element erased by the function
call, which is the vector end if the operation erased the last element
in the sequence.
http://cplusplus.com/reference/stl/vector/erase/
It is not a good idea to modify the vector (to move around components and changing the vectors length in this case) you are iterating over. That is the problem with your code. When you remove one component in the middle of the vector, the ones at the end are shifted to the left, so the end of the vector moves. That messes up your break condition.
Instead of modifying your existing vector, you could create a new vector empty vector, and add to it every component you want to keep. That could consume more memory (if your vector is large, that might be of interest), but it should save you much cpu-time, because removing a component in the middle of the vector is not a cheap operation. All components right of it have to be moved, again and again, one position at a time (there exist containers in stl that don't have this problem). So building a new vector and adding to it should be better altogether.

Keeping std::list iterators valid through insertion

Note: This is not a question whether I should "use list or deque". It's a question about the validity of iterators in the face of insert().
This may be a simple question and I'm just too dense to see the right way to do this. I'm implementing (for better or worse) a network traffic buffer as a std::list<char> buf, and I'm maintaining my current read position as an iterator readpos.
When I add data, I do something like
buf.insert(buf.end(), newdata.begin(), newdata.end());
My question is now, how do I keep the readpos iterator valid? If it points to the middle of the old buf, then it should be fine (by the iterator guarantees for std::list), but typically I may have read and processed all data and I have readpos == buf.end(). After the insertion, I want readpos always to point to the next unread character, which in case of the insertion should be the first inserted one.
Any suggestions? (Short of changing the buffer to a std::deque<char>, which appears to be much better suited to the task, as suggested below.)
Update: From a quick test with GCC4.4 I observe that deque and list behave differently with respect to readpos = buf.end(): After inserting at the end, readpos is broken in a list, but points to the next element in a deque. Is this a standard guarantee?
(According to cplusplus, any deque::insert() invalidated all iterators. That's no good. Maybe using a counter is better than an iterator to track a position in a deque?)
if (readpos == buf.begin())
{
buf.insert(buf.end(), newdata.begin(), newdata.end());
readpos = buf.begin();
}
else
{
--readpos;
buf.insert(buf.end(), newdata.begin(), newdata.end());
++readpos;
}
Not elegant, but it should work.
From http://www.sgi.com/tech/stl/List.html
"Lists have the important property that insertion and splicing do not invalidate iterators to list elements, and that even removal invalidates only the iterators that point to the elements that are removed."
Therefore, readpos should still be valid after the insert.
However...
std::list< char > is a very inefficient way to solve this problem. Each byte you store in a std::list requires a pointer to keep track of the byte, plus the size of the list node structure, two more pointers usually. That is at least 12 or 24 bytes (32 or 64-bit) of memory used to keep track of a single byte of data.
std::deque< char> is probably a better container for this. Like std::vector it provides constant time insertions at the back however it also provides constant time removal at the front. Finally, like std::vector std::deque is a random-access container so you can use offsets/indexes instead of iterators. These three features make it an efficient choice.
I was indeed being dense. The standard gives us all the tools we need. Specifically, the sequence container requirements 23.2.3/9 say:
The iterator returned from a.insert(p, i, j) points to the copy of the first element inserted into a, or p if i == j.
Next, the description of list::insert says (23.3.5.4/1):
Does not affect the validity of iterators and references.
So in fact if pos is my current iterator inside the list which is being consumed, I can say:
auto it = buf.insert(buf.end(), newdata.begin(), newdata.end());
if (pos == buf.end()) { pos = it; }
The range of new elements in my list is [it, buf.end()), and the range of yet unprocessed elements is [pos, buf.end()). This works because if pos was equal to buf.end() before the insertion, then it still is after the insertion, since insertion does not invalidate any iterators, not even the end.
list<char> is a very inefficient way to store a string. It is probably 10-20 times larger than the string itself, plus you are chasing a pointer for every character...
Have you considered using std::dequeue<char> instead?
[edit]
To answer your actual question, adding and removing elements does not invalidate iterators in a list... But end() is still going to be end(). So you would need to check for that as a special case at the point where you insert the new element in order to update your readpos iterator.

Iterator and 2d vector

vector< vector<int> >::iterator temp = mincost.end();
vector<int> a = *temp;
if ( *temp != *(temp--) )
return 0;
mincost is a 2d vector, I want to get the last vector<int> of this vector and last--.
I don't really understand about iterator :) . Help me !! :D
Thx ^^
minconst.end() points to the element one-past-the-end of the vector minconst; it doesn't point to the last element in the vector.
Since you want the last two elements, you should first test to be sure the vector actually has two elements in it, otherwise inevitably you'll run into problems. Then, accessing the last elements in the vector is simply a matter of *(minconst.end() - 1) and so forth.
The C++ Reference also has a description of iterators.
It would probably be helpful to learn about iterators in general.
A quick google search leads to many good references, not the least of which is
http://www.cppreference.com/wiki/stl/iterators
Good luck!
If you're new to STL containers, think of the end() iterator as something like the '\0' character in C-strings - they define where the end is, but the actual value they carry isn't useful. If you dereference the end iterator, you'll get junk, or most probably an exception.
Try this:
if (!mincost.empty())
{
//it contains atleast one 1-d vector and the 'end' iterator.
iter = mincost.end();
--iter;
//dereference iter here.
}
Once you're comfortable with thinking in terms of iterators, look up the reverse_iterator. As Effo mentioned, they are the best solution here.