How to understand how iterator and .end() work in c++? - c++

I'm learning c++ newly, and can't figure out the iterator... for instance, I have the code below with a map and, despite research, can't figure out the .end(), iterator it as well as first
std::map<int, double> e;
e[1] = 10.0;
e[2] = 20.0;
e[3] = 30.0;
e[4] = 40.0;
map<int, double>::iterator it;
it = e.end();
it--;
int d = 1.0*it->first / 50000;
Could someone indicates me the meaning of each step of this code, from the map initialization to the last line ! Thanks !

Iterators are used to point at the memory addresses of STL containers.
.begin() points to the first element of container address.
.end() points to the last element of container address + 1.
this link explain iterator :
iterator

For simplicity, you can imagine a map using this visualization
[X,X,X,X,X,X,X]_
A B
map.begin() will return a pointer to point A
map.end() will return a pointer to point B
An element in a map is a pair of (key, value). Thus, first refers to the key.
All elements in a map is sorted based on the key. Thus, your code is trying to get the maximum key divided by 50000

Related

why C++ lower_bound() allows return pointer equivalent to val while upper_bound() does not

I read the description for C++ upper_bound() function and lower_bound() function. It is interesting for me that upper_bound() only returns the first iterator with value > val (or return last iterator in the range [first, last) if val not found).
The implementation is different from lower_bound(), while it returns the first iterator NOT SMALLER than val, so it allows the return pointer equivalent to val.
I am just curious to know what is the purpose to design upper_bound() in this way that upper_bound() must NOT return an iterator with value equivalent to val?
For example:
vector<int> a = {1, 2, 3, 4};
auto i = lower_bound(a.begin(), a.end(), 2); // i is iterator at 2;
auto j = upper_bound(a.begin(), a.end(), 2); // j is iterator at 3;
http://www.cplusplus.com/reference/algorithm/lower_bound/
In C++, iterators usually work in pairs. The first iterator points to the first element to consider, and the last iterator points to one-past-the-last element to consider. This is to make looping easy:
for(it cur=first; cur!=last; cur++)
As such, lower_bound and upper bound together, form a "range of all elements equal to the item you searched for. The same range that std::equal_range returns.
upper_bound is useful in cases like std::multimap where values are stored in sorted order. It lets you traverse within a range where starting position can be decided by lower_bound, and end-before-this-position is decided by upper_bound.
for (iter_type it = myMap.lower_bound("key_val"); it != myMap.upper_bound("key_val"); it++)
This for loop would traverse till the point key == key_val.

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.

C++ list iterator to integer conversion?

Hello guys I have a list iterator type which I want to convert to UINT.
std::set<UINT> volSet;
UINT ssidBase = 1;
UINT ssidEnd = 2;
volSet.insert( ssidBase );
volSet.insert (ssidEnd);
UINT ssidStart = evf::volSet.begin();
I want the first value in the volSet to be set to ssidStart. I'm getting an error when I run this?
cannot convert 'std::_Tree<std::_Tset_traits<unsigned int, std::less< unsigned int>, std::allocator< unsigned int>, false> >::iterator' to 'UINT' in initialization
Any help is appreciated?
As such, iterators in C++ are basically pointers.
So the general idea is that you need to dereference that iterator to access the actual value it points to, like so:
UINT number = *(container.begin());
It is not clear exactly what the intention is with inserting a one and then a two. Granted many more unsigned values can be inserted later. However, by inserting a one, the only other possible value that will be lower is zero. The insert method for the STL set, map, unordered_set, and unordered_map containers (now called Standard Library) returns a pair.
Insert method reference links:
set
http://www.cplusplus.com/reference/set/set/insert/
map
http://www.cplusplus.com/reference/map/map/insert/
unordered_set
http://www.cplusplus.com/reference/unordered_set/unordered_set/insert/
unordered_map
http://www.cplusplus.com/reference/unordered_map/unordered_map/insert/
If the element already exists in a set, the first pair element is the iterator pointing to the existing element with the second element set to false. With a successful insert (e.g. the key is not already present in the set), the first element of the pair points to the element that has been successfully added, with the second pair element set to true.
Using a set to guarantee the first (lowest) element (e.g. where the begin() method will always return an iterator pointing to unless the set is empty), does guarantee that the lowest value in the set is always found in constant time (e.g. O(1); big Oh of one).
A coding example with some values in C++11.
std::set<UINT> volSet;
pair <std::set<UINT>::itertor, bool> p;
//
// Using the same notation on unsigned int for consistency,
// insert 500 unsigned values into the volSet container.
//
for (UINT i = 500; i >= 0; i--)
{
p = volSet.insert(i);
if (p.second == false)
{
cerr << "volSet insertion warning!! The value for volSet already has: ";
cerr << i << endl;
}
}
//
// Do business logic, deletions/insertions from/to the volSet, and so on...
//
// Now obtain the lowest value inside the volSet and set it to a local variable.
// It is assumed that evf is a user defined namespace.
//
std::set<UINT>::iterator ii = evf::volSet.begin();
UINT ssidStart = *ii;
//
// Alternatively, implement without declaring a local iterator as Victor
// has shown above. Note that the parenthesis here are important. The call
// to begin() has to occur prior to the dereference operator call.
// Note that the sample above intentionally sets the ii iterator
// before dereferencing.
//
UNIT lowValue = *(evf::volSet.begin());
I hope this is helpful to understand the difference between iterators and container elements.

Referencing max/min int in set for c++

Say that I have the following example using a set in c++:
set <int> a;
for (int i = 0; i <10; i++){
//Assume i is a random number
a.insert(i);
}
How can you find the maximum and minimum values for the set example shown above? Ideally I thought that the following would work but it gives the following error:
error: cannot convert 'std::_Rb_tree_const_iterator<int>' to 'int' in assignment
I'm using the following functions to try getting max/min:
min = a.begin();
max = a.end();
First of all, begin and end return iterators, which you need to perform indirection on (*) to get the element they point at.
Secondly, end returns the past-the-end iterator, so doesn't actually refer to the last element. You can instead use the reverse begin iterator.
min = *a.begin();
max = *a.rbegin();
a.begin() and a.end() are iterators, not elements. Use
min = *a.begin();
to receive min element and
max = *a.rbegin();
to receive max.
max = *a.end();
will not work because it points on the next element after the last one. So it will return garbage.
As others have said, an iterator (as the one returned by begin() or rbegin()) must be dereferenced to retrieve the value it points to.
But, before dereferencing, the iterator must be checked for validity. For example, on an empty vector begin() will return an out-of-range iterator (pointing one position past the last).
So, a more cautious way would be:
// assuming a is a vector<int>
vector<int>::const_iterator p = a.cbegin(); // or use auto to hide iterator type
int min_val = p != a.cend()? (*p) : (INT_MAX); // if empty, yield a special value like INT_MAX

C++ - How to know if there is no returned value from a map::upper_bound()?

I've got a very simple map :
std::map<int, double> distances;
distances[20.5] = 1;
distances[19] = 2;
distances[24] = 3;
How do i know if there isn't any returned value, when using a map::upper_bound() in this case for example:
std::map<int, double>::iterator iter = distances.upper_bound(24);
(24 is the max key so an unexpected result is returned, but how to know that through the code ? How to know i've reached the max key ?).
Thanks !
if (iter == distances.end())
// no upper bound
Most iterators in C++ will be set to the end of the collection to represent an absent value. This is the only valid value for an iterator to represent "no more data".
So you can compare iter with distances.end(), and if they are equal, then you've got your answer.
It's distances.end(), which makes perfect sense. Intuitively, upper_bound() returns the iterator that points to the first place which is "after" where your key is or would be in the map. If all the keys in the map are less than or equal to your key, then the first place that is "after" all of them is the end iterator.