Any one could explain me what is the meaning of past-the-end. Why we call end() function past-the-end?
The functions begin() and end() define a half open range([begin, end)), which means:
The range includes first element but excludes the last element. Hence, the name past the end.
The advantage of an half open range is:
It avoids special handling for empty ranges. For empty ranges, begin() is equal to
end() .
It makes the end criterion simple for loops that iterate over the elements: The loops simply
continue as long as end() is not reached
Because it doesn't point to the last element of a container, but to somewhere past the last element of a container.
If you dereference end() it results in undefined behaviour.
Like interval in mathematics, stl uses [begin, end).
That's why we could write for (auto it = v.begin(); it != v.end(); ++it)
Literally, because it points one past the end of the array.
It is used because that element is empty, and can be iterated to, but not dereferenced.
int arry[] = {1, 2, 3, 4, /* end */ };
^^^^^^^
std::end(arry) would point here.
Adding another point to the above correct answers.
This was also done to be compatible with arrays.
For example in the code below:
char arr[5];
strcpy(arr, "eakgl");
sort(&arr[0], &arr[5]);
This will work fine.
Instead if you had given :
sort(&arr[0], &arr[4]);
it would miss sorting the last character.
This also helps to represent empty containers naturally.
Related
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.
I am not proficient in C++ but I am converting a short script to PHP
for(auto it = First; it != Last; ++it)
{
Result += *it;
}
From this snippet, I can speculate this simply means
Result = Result + it
where * is a reference to the pointer of the loop.
That said I see this symbol used outside of loops and in some cases I see variables without this symbol both in and outside of loops which puts holes in my theory.
Again I am trying to RTFM but I am unsure what I am searching for.
Both First and Last are iterator objects, representing a generalization of pointers in C++ Standard Library. Additionally, the two iterators reference the same collection, and Last can be reached from First by incrementing the iterator*.
Result is some sort of accumulator. If it is of numeric type, += means Result = Result + *it, where *it is whatever the iterator is pointing to. In other words, Result accumulates the total of elements of the collection between First, inclusive, and Last, exclusive. If First points to the beginning of an array and Last points to one-past-the-end of an array of numeric type, your code would be equivalent to calling PHP array_sum() on the array.
However, Result is not required to be numeric. For example, it could be a std::string, in which case += represents appending the value to the string.
* In terms of pointers and arrays this would be "pointing to the same array," and "Last points to a higher index of the array than First."
I believe your speculation is incorrect.
it, first and last are either iterators or pointers. Iterators are C++ objects that can be used to iterator over containers. For basic usage, they behave much like pointers, and can be dereferenced the same way.
For example:
std::vector<int> myList;
...
// Search for the number 10 in the list.
std::vector<int>::iterator it = std::find(myList.begin(), myList.end(), 10);
// If the number 10 was found in the list, change the value to 11.
if (it != myList.end())
*it = 11; //< Similar to pointer syntax.
In your specific example, the Result variable has a value added to it. To get that value, your code uses the * operator to get the value from the iterator.
The same concept applies to pointers. although iterators and pointers are very different concepts, accessing their values is very similar.
First: I am happy to update the question in the title if someone can think of a more concise way to put it.
Here's the situation:
I have a vector as class member. After extracting an element from the vector with the following:
inline int currentToken()
{
/* __it is of type std::vector <int>::iterator */
return (__it < __tokens.begin()) ? Syntax::OUT_OF_RANGE_BEGIN :
(__it > __tokens.end()) ? Syntax::OUT_OF_RANGE_END :
*__it;
}
The returned integer is exactly as expected (in this case, a 65, which is what it should have been).
Now is where things get tricky, however. When this particular token is encountered, it sparks a new chain of events and the previous tokens in the vector need to be discarded.
First, I call the class' 'saveLocation' member function, which is an inline quickie:
__saved_it = __it;
Then, I call the 'truncateHead' member function, which is where the error occurs. Before the code, I would like to point out that none of the above has in any way changed the vector, so there is absolutely no reason for the vector's memory to have been reallocated.
__it = __tokens.erase(__tokens.begin(), __saved_it+1); //segfault
Some debugging has revealed that somehow __it is greater than __tokens.end(), even though it is still both larger than __begin and dereferenced to the number '65' as expected.
How is it not in the range between __tokens.begin() and __tokens.end()?
In fact, this situation is already present in the saveLocation method above.
Remembering that currentToken() is immediately followed by saveLocation(), and currentToken would have returned the integral representation of OUT_OF_RANGE_END if the iterator were already out of range, I am flummoxed.
Completely and utterly.
tokens.end() returns a past the end iterator. That is, it is already outside of the range.
It's not meaningful to compare if an iterator is bigger than (>) a past the end iterator, as iterators only range from begin() to end(). Because of the same reason, it is also not meaningful to check if an iterator is less than the iterator returned by begin().
This means that there's no way of checking if an iterator is OUT_OF_RANGE_BEGIN or OUT_OF_RANGE_END. You can only check if it's inside the valid range or not.
It's ok to check if an iterator is bigger than or equal to (>=) the iterator returned by begin().
When you check if __it is past the last element then you should evaluate if the iterator is not equal to tokens.end()
E.g. you should check for something like
return (__it >= __tokens.begin()
&& __it != __tokens.end()) ? *__it : Syntax::OUT_OF_RANGE;
This also requires that you do not increment the iterator past the containers past-the-end-iterator. Accessing memory pointed to by an iterator that has been incremented past the end()-iterator will result in undefined behaviour.
Iterator comparisons are only valid for iterators that point into the same range. Testing whether an iterator is < the begin iterator of a container or > the end iterator of a container does not do anything meaningful.
Say I have the following code:
typedef std::map< int, std::string >::iterator Iterator;
Iterator iter = myMap.begin();
while (iter != myMap.end())
{
Iterator current = iter;
++iter;
maybeDeleteElement( current ) // may call erase.
}
Given that std::map is implemented as a red-black tree, is it guaranteed that every element in the map will be visited exactly once? Or will modifying the map cause the tree to rebalance, and thus the iteration sequence to change?
Note: This is not a question about whether or not any iterators will be invalidated. But an iterator remaining valid does not necessarily mean that incrementing it will give you the same next element that it did before.
In a std::map the elements will be visited in order.
If you store an iterator that refers to an element that is not deleted, and hence not invalidated, the iterator will still refer to that same element. (If it was the end iterator, it remains the end iterator, as it is not invalidated).
When you advance that iterator, it will advance to the next element in order after the element you refer to.
For your particular example, yes, every element will be visited exactly once, because all deletion of elements was elements that are before the current iterator state of your loop.
If you insert elements ahead of whatever iterator you are using to iterate, then you'll eventually reach them as you iterate forward with your iterator. If you delete elements ahead of whatever iterator you are using to iterate, then they are no longer part of the future elements you'll reach if you iterate with that iterator.
If you insert or delete elements that are before the current location of the iterator, unless you start calling -- or similar functions, your current iteration will continue without noticing that they went away.
This is because ++ on a valid iterator in an ordered container is guaranteed to return the next element in the order, and operations on other iterators that do not invalidate an iterator don't change that iterator's invariants (like what element they refer to).
Yes, inserting/erasing can modify the iteration sequence. It does not happen in your example, as you erase iterators you've already passed by, but if you erase/insert elements that are positioned ahead of your current iterator, then it will modify the rest of the sequence.
Here is a short code which displays such behavior:
int main (){
map<int,int> mapa;
for(int i = 0; i < 5; ++i) mapa[i] = i;
bool add = false;
for(auto it = mapa.begin(); it != mapa.end(); ++it){
int x = it->second;
printf("%d\n", x);
if(add) mapa.erase(x+1);
add = !add;
}
return 0;
}
The example above will print 0 1 3 4 (instead of 0 1 2 3 4). Additionally, if you erase the current iterator, its reference to the next element will be invalidated and your program will crash at the next iteration.
Alternatively, you can also test the insertion, by substituting the if(add) above with:
if(add) mapa[x+5] = x+5;
else mapa[x-20] = x-20;
The example will print the extra elements {6, 8, 11, 16}, and not print the negative ones, since those are being inserted in a position prior to your current one.
Erasing an element from a map does not invalidate iterators, so I would expect it to continue to iterate properly.
See https://stackoverflow.com/a/6438087/5987
Yes, the iteration sequence changes. This is due to ยง23.2.4.1/10 and /11:
(p10) The fundamental property of iterators of associative containers is that they iterate through the containers in the non-descending order of keys where non-descending is defined by the comparison that was used to construct them. For any two dereferenceable iterators i and j such that distance from i to j is positive,
value_comp(*j, *i) == false
(p11)
For associative containers with unique keys the stronger condition holds,
value_comp(*i, *j) != false.
If, after an insert, the new element were added at the beginning of the iteration sequence regardless of the ordering of elements (so as to not to modify the sequence ahead of any existing iterator position), the above requirement would be violated.
In spite of your note, for the erase case this question is exactly about iterator invalidation, because if no iterator is invalidated, the order necessarily remains the same. This is because map is a sorted container, so no matter what internal representation changes may happen, the iteration order has to remain exactly the same.
To address specifically your example, it will traverse each element exactly once, because you save off the iterator to check and increment your traversal iterator.
In the case of insertion, if you insert before the current point of iteration that element won't be visited. Inserting after the current iterator will result in the new item being traversed.
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.