Iterator from both ends of a Vector - c++

I have a vector of IntRect: vector.
How can I iterate from both ends of the list and stop the iterator when the iterator intersects?
vector<IntRect>::iterator itr = myVector.begin();
vector<IntRect>::reverse_iterator revItr.rbegin();
for (; /*check itr and revItr does not intersect, and itr and revItr do not end */ ; ++itr, ++revItr) {
IntRect r1 = *itr;
IntRect r2 = *revItr;
// do something with r1 and r2
}
Thank you.

if(!myVector.empty()) {
for(vector<IntRect>::iterator forwards = myVector.begin(),
backwards = myVector.end()-1;
forwards < backwards;
++forwards, --backwards) {
// do stuff
}
}
I think you need to check empty() with that implementation - suspect that end()-1 isn't defined if the vector is empty. I haven't used it before, but Dinkumware STL at least has operator < defined for vector iterators and it appears to do something sensible.
Also note that you need to check <, not just equality - that takes care of the (common) case where your vector has an even number of entries and the two iterators would step past one another.

You can use base function on the reverse iterator and compare the result with your forward iterator.
Remember that if you're moving both iterators, they will never be equal if the sequence has odd number of elements. You have to check the equality twice in each iteration.

None of the answers that I've seen account for the two iterators "passing in the night."
vector<IntRect>::iterator forward = myVector.begin(), backward = myVector.end();
while (forward != backward)
{
++forward;
// at this point they could be equal
if (forward == backward)
break;
--backward;
}

Your iterators point to the same thing if &(*itr) == &(*revItr)
Assuming nobody has done something stupid and overloaded operator& on IntRect.

I would replace the second (reverse) iterator with a regular one and have that initialised to --myVector.end(). Instead of incrementing it, decrement it and compare the iterator values.

Related

Iterating in reverse direction using rbegin() and begin()

When we are iterating in reverse direction, I see that most people use the following structure:
for (auto it = vec.rbegin(); it != vec.rend(); it++)
{
// block of code //
}
But for a long time, I have a doubt about using this, and I want to know why the following code does not work.
As we know, the last element will have the highest index than any element index in the array, and the array is going to take contiguous memory.
My primary doubt is when iterating backwards, why shouldn't we use it--?
I want the reason why the following code is not going to work. I am running the loop from rbegin, that is the last element, and I am going until the first element. I am decrementing it by one in every iteration.
for (auto it = vec.rbegin(); it >= vec.begin(); it--)
{
cout << *it << endl;
}
Even the below code is not working, why?
for(auto it = vec.rbegin(); it >= vec.begin(); it++)
{
cout << *it << endl;
}
First of all, in the given codes, the for loop's conditions are making issue due to type-mismatch.
The vec.rbegin() gives the std::vector::reverse_iterator, and the vec.begin() gives the std::vector::iterator; those are different types and can not be compared. Hence, you get compiler errors in those places.
When iterating backwards, why shouldn't we use it--?
See the following reference picture from std::reverse_iterator
When you use rbegin(), you start from the last element. In order to advance further (like every iterator implementation) it uses the operator++. Advance here means, iterating backwards direction, because the starting point is the last element. Therefore, you should be using it++ or ++it instead.
For the last for loop example, however, there is only a type-mismatch issue. Using ✱std::reverse_iterator::base(), you could get/ convert the reverse iterator to the corresponding base iterator, and it can be compared with the vec.begin().
That means the following change will make it work:
for (auto it = vec.rbegin(); it.base() != vec.begin(); ++it)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
std::cout << *it << " ";
}
See a demo
Side Note:
Even though, the above is possible, I would strongly suggest use the same iterators for comparison, which provides the code more natural look, and easy to understand for the fellow devs and less error-prone.
✱Read more: Can I convert a reverse iterator to a forward iterator?
In all, it is just a design issue, the designer designed the begin, rbegin, end, rend in that way.
Take an example of a container with three elements {1,2,3}.
begin() points to 1, end() points to the position after 3
rbegin() points to 3, rend() points to the position before 1.
You can understand rbegin() as a special data struct of a special pointer (aka iterator) such that + operator would be overloaded into -.
You can but not recommended to mix rbegin() with begin() cause they are different things. And mixing is always error-prone for most of the time.
Reverse iterators are designed to mimic forward iterators (and iterators in general are designed to mimic pointers), so algorithms can be written in an agnostic way that works with both types. All iterators advance with operator++ and decrement with operator-- , where
forward iterators advance in a forward direction and decrement in a backwards direction
reverse iterators advance in a backward direction and decrement in a forward direction

Confusion in concept of iterator in map in C++

Suppose I have a map named m and an iterator i for the map. Presently I am visualising a map iterator as an array index and I want to implement a code like the one given below:
for(auto i = m.begin(); i != m.end(); i++) {
auto l = i - 1; // error type 1
auto r = i + 1; // error type 1
while(l >= m.begin() && r < m.end()) { // error type 2
// ...
r++;
l--;
}
}
Now, I have got some questions which has been confusing me a bit.
For the error type 1 stated in the code, incrementing or decrementing the iterator value gives error, but the similar operation done within the loop (I mean to say i++) gives no error.
For error type 2, why does comparing two iterators (l >= m.begin()), straight up give error, but doing the similar operation in a loop does not give error?
And finally, how could I make this code work on the lines of how an array index works using this map? I hope you can understand what I am trying to implement.
Iterator for std::map is defined by standard as Bidirectional Iterator. This type of iterators can be incremented(operator ++) and decremented (operator --), but you can't perform mathematical operations on them (mostly because it would take O(n) time rather than O(1))
And again, for error 2, bidirectional iterator does not overload < operator (nor other variations), as it doesn't make sense to have compare operator with O(n) complexity. They are overloaded in random access iterators at the lowest.
To achieve what you wanted, your code can look like this:
#include <iterator> /for std::next() and std::prev()
for(auto i = m.begin; i != m.end(); ++i)
{
auto l = i;
auto r = i;
if (i != m.begin())
l = std::prev(i);
if (i != m.end())
r = std::next(i);
while (l != m.begin() && r != m.end())
{
//make sure you don't use r if it's equal to m.end()
--l;
++r;
}
Map is an associative container. The following containers are defined in the current revision of the C++ standard with associative container: set, map, multiset, multimap.
Associative Containers support bidirectional iterators. Bidirectional iterators are iterators that can be used to access the sequence of elements in a range in both directions (towards the end and towards the beginning). They are similar to forward iterators, except that they can move in the backward direction also, unlike the forward iterators, which can move only in forward direction.
Bidirectional iterators support following operations:
Is default-constructible, copy-constructible, copy-assignable and
destructible X a; X b(a); b = a;
Can be compared for equivalence using the equality/inequality
operators (meaningful when both iterator values iterate over the same
underlying sequence). a == b a != b
Can be dereferenced as an rvalue (if in a dereferenceable state).
*a a->m
For mutable iterators (non-constant iterators): Can be dereferenced
as an lvalue (if in a dereferenceable state). *a = t
Can be incremented (if in a dereferenceable state). The result is
either also dereferenceable or a past-the-end iterator. Two iterators
that compare equal, keep comparing equal after being both increased.
++a a++ *a++
Can be decremented (if a dereferenceable iterator value precedes it).
--a a-- *a--
So, + and - is not defined for it, which leads to the error1.
And so is >=, <=, >, < not defined for it, which leads to error2.
The problem is iterator doesn't work like array indices. The elements of map will be stored at different locations in memory and there is no guarantee that the between elements i and j in map, if i comes before j, then it will be stored in memory just before j. The values are not stored at consecutive locations in memory in case of map.
The ++ operator is overloaded for iterators and it will give the proper location of the next element.
Also, if you consider the points above, then comparing two iterators makes no sense because the fact that one iterator comes after another doesn't give us any important information regarding the corresponding values that will be accessed using these two iterators.
there are different iterator categories/concepts: Iterator, ForwardIterator, BidirectionalIterator, RandomAccessIterator and ContiguousIterator. They differ in available operations. Simple iterators only support step forward (operator ++), dereference (operator *) and inequality comparison (operator !=). This is the required minimum for range-based for loop. std::map::iterator is BidirectionalIterator - it doesn't support arithmetic or comparison operators.
Solving the x-y problem: I want to do "this", I wrote code that does "that"
So I presume you really do want to have access to the previous element in the map, and the next element. I presume you only want this when those 2 elements are "good"
You could recast your loop to cascade the knowledge of the 3 neighbouring iterators:
for(auto r = m.begin(), e= m.end(), i= e, l= e; r != e; l =i, i =r, r++)
{
if (l != e)
{
// All 3 iterators are good here
}
}

Accessing an element and its successor in a list at the same time

I have a list and when iterating over it i want to access the element at the iterator and the following element at the iterator+1 at the same time. Here is my attempt:
std::list<Team*> teamlist = league.GetTeamMembers();
for (std::list<Team*> ::iterator iterator = teamlist.begin(); iterator != teamlist.end(); std::advance(iterator,2))
{
match(*(*iterator), *(*(++iterator)));
}
The match function does nothing to the iterators, it just get's some values of the teams out of it to calculate a match result.
But the ++iterator does not work, as the elements in the matchfunction are still the same. How do I do this?
Passing the iterator and operating on the iterator in the same pass (like increment of the iterator) leads to undefined behavior. There are certain concepts such as sequence points, which you should be aware of when you are performing such operations.
Further, you can check this link also. I suggest you to move the increment of the operator after the pass to function. Then it should work fine.
You could avoid increasing the iterator at increment part of the loop and dot it in the body:
std::list<Team*> teamlist = league.GetTeamMembers();
for (std::list<Team*> ::iterator it = teamlist.begin();
it != teamlist.end(); /*Nothing here*/)
{
match(*(*it), *(*(++it))); //Which parameter expression is evaluated first isn't determined
++it;
...
...
EDIT:
As FredOverflow has pointed out, match parameter expressions evaluations are not guaranteed to run in the left to right order. To avoid this hazardous situation:
std::list<Team*> teamlist = league.GetTeamMembers();
for (std::list<Team*> ::iterator it = teamlist.begin();
it != teamlist.end(); /*Nothing here*/)
{
Team *pa = *it;
Team *pb = *(++it);
match(*pa, *pb);
++it;
...
...
you are increasing the iterator twice, first in the head of the for-loop:
std::advance(it,2)
then in the loop-body, where you do a:
++it
Is this really what you want? It looks pretty confusing to me.
If you want the element next to it, but dont want to increase it, better use:
auto nextIt = std::next(it);
Also: What does the match-function do? Are you sure its implemented right and not the source of the bug?
Hope this helps
Alexander

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.

How can I check if this is last member of std::list?

I have a list like below
typedef std::list<std::string> SegmentValue;
then in a iteration I need check if this is last iteration.
for(Field::SegmentValue::const_iterator it = m_segmentValue.begin();It !=
m_segmentValue.end();It++){
if((segIt + 1) == m_segmentValue.end())//last iteration
...
}
but I get error in compile that:
error C2678: binary '+' : no operator found which takes a left-hand operand of type 'std::list<_Ty>::_Const_iterator<_Secure_validation>'
how I can check if this is last itration?
You can't use binary + and - operators with std::list iterators. std::list iterators are bidirectional iterators, but they are not random access iterators, meaning that you can't shift them by an arbitrary constant value.
Use unary ++ and -- instead
Field::SegmentValue::const_iterator it_last = m_segmentValue.end();
--it_last;
Now it_last is the last element iterator. Just make sure it remains valid. If you are not making any iterator-invalidating modifications to your container, you can pre-compute it_last and use it in the cycle. Otherwise, you'll have to re-compute it as necessary.
In fact, in generic algorithms it is always a good idea to prefer using -- and ++ with iterators whenever possible (instead of binary + 1 and - 1), since it reduces your algorithm's requirements: binary + and - require random access iterators, while ++ and -- work with bidirectional ones.
Use std::next:
if (std::next(segIt) == m_segmentValue.end()) ...
If you're using C++03, you can easily write next yourself:
template<typename T> T next(T it, typename std::iterator_traits<T>::difference_type n = 1) {
std::advance(it, n);
return it;
}
Something like this perhaps:
Field::SegmentValue::const_iterator last = m_segmentValue.end()
--last;
for(Field::SegmentValue::const_iterator it = m_segmentValue.begin();
It != m_segmentValue.end();
It++) {
if(It == last) {
// last iteration
}
}
You can only do arithmetic with Random Access Iterators. std::list's iterators are Bidirectional.
See here for what you can and cannot do with iterators of various categories.
Try this:
Field::SegmentValue::const_iterator next = it; ++next;
// or in C++11:
// Field::SegmentValue::const_iterator next = std::next( it );
if( next == m_segmentValue.end()) //last iteration
List iterators are Bidirectional, not RandomAccess so they don't support operator+.
std::list iterator are not random access, they are bidirectional. The operator+ is not supported. You need to use std::vector to do something like that.
How about:
if ( &*it == &*(m_segmentValue.rbegin()))
i.e, comparing the addresses of the segments.