value_comp and * before a iterator - c++

What does the value_comp do, like does it check the first value equal to the second?
and * operator before the iterator?
map<char, char> m =
{
{ 'a', 'A' },
{ 'b', 'B' },
{ 'c', 'C' },
{ 'd', 'D' },
{ 'e', 'E' },
};
auto last = *m.rbegin(); // How does "*" affect the iterator returned
auto i = m.begin();
do
{
cout << i->first
<< " = "
<< i->second
<< endl;
} while (m.value_comp()(*i++, last));
// Does the value_comp compares *i++ and the last value or iterator

How does "*" affect the iterator returned?
It dereferences the iterator and gives the pointee. Meaning the last has type
std::pair<const char, char>
or
decltype(m)::value_type // or std::map<char, char>::value_type
If you would have just auto last = m.rbegin(); (i.e. without dereferencing), you would get the iterator there, meaning the last would have deduced to std::map<char, char>::iterator.
Does the value_comp compares *i++ and the last value or iterator?
std::map::value_comp returns:
a function object that compares objects of type
std::map::value_type (key-value pairs) by using key_comp to
compare the first components of the pairs.
Therefore, it compares the values of the map, not the iterator pointing to the key-value pairs.

So, it looks like you have basically two questions:
auto last = m.rbegin(); //How does "" affect the iterator returned
The "*" operator returns the reference of value_type which for your map would be std::pair<const char, char>.
Does the value_comp compares *i++ and the last value or iterator
value_comp() returns the function that compares keys in objects of type value_type. So, in your code it compares keys i->first and last.first. It returns true if the first key is less

How does "*" affect the iterator returned?
The dereference (*) means that the value stored in last is not the iterator, but a copy of what's stored at that position in the map, which incidentally is the last node of the map. It works much in the same way as dereferencing a pointer, you get the value pointed by it, not the pointer itself.
Does the value_comp compares *i++ and the last value or iterator?
Yes it does. It compares the two keys, the one "pointed by" i and the one stored in last. The method will return true as long as the first argument key is at a lower position on the map than the key of the second argument.
In your example, when the keys match the cycle ends.
As per the description of the method:
It returns a comparison object that can be used to compare two elements to get whether the key of the first one goes before the second.
The comparison object returned is an object of the member type map::value_compare, which is a nested class that uses the internal comparison object to generate the appropriate comparison functional class.
Side note:
It may be clear that *i++ also returns the content of i, and the iterator i is being incremented at each iteration, but this expression can cause confusion, you could use brackets to avoid it, like so *(i++).

Related

How is the value object constructed in case key is not present while using [] operator for an unordered_map?

In an unordered_map, when we use the [] operator to get the value for a key, then if the key is not present, it performs an insertion. I want to understand how it is implemented.
std::unordered_map<int, int> x;
x[1] = 10;
In the above statement, how is the rvalue 10 accessed and used to perform an insertion ?
Very straightforward.
Operator [] for std::map and std::unordered_map looks for an element with a given key. If the element is present, it returns the reference to the second member of it's pair. If it is not present, it creates a new pair, with a key (first) equal to given key and value-initialized second, inserts this element and returns reference to the second.
Then operator= works normally.

Mechanism of using sets as keys to map

I have this code which I do not understand why it works:
map<set<int>,int> states;
set<int> s1 = {5,1,3}, s2 = {1,5,3};
states[s1] = 42;
printf("%d", states[s2]); // 42
The output is 42, so the values of the states key are used for comparison somehow. How is this possible? I'd expect this not to work as in the similar example:
map<const char*,int> states;
char s1[]="foo", s2[]="foo";
states[s1] = 42;
printf("%d",states[s2]); // not 42
Here the address of the char pointer is used as the key, not the value of the memory where it points, right? Please explain what's the difference between these two samples.
Edit: I've just found something about comparison object which explains a lot. But how is the comparison object created for sets? I can't see how it could be the default less object.
You were up to something with the comparison object.
One of the template parameters for a C++ map defines what acts as the comparison predicate, by default std::less<Key>, in this case std::less<set<int>>.
From cplusplus.com:
The map object uses this expression to determine both the order the elements follow in the container and whether two element keys are equivalent (by comparing them reflexively: they are equivalent if !comp(a,b) && !comp(b,a)). No two elements in a map container can have equivalent keys.
std::less:
Binary function object class whose call returns whether the its first argument compares less than the second (as returned by operator <).
std::set::key_comp:
By default, this is a less object, which returns the same as operator<.
Now, what does the less-than operator do?:
The less-than comparison (operator<) behaves as if using algorithm lexicographical_compare, which compares the elements sequentially using operator< in a reciprocal manner (i.e., checking both a<b and b<a) and stopping at the first occurrence.
Or from MSDN:
The comparison between set objects is based on a pairwise comparison of their elements. The less-than relationship between two objects is based on a comparison of the first pair of unequal elements.
So, since both sets are equivalent, because sets are ordered by key, using either as key refers to the same entry in the map.
But the second example uses a pointer as key, so the two equivalent values aren't equal as far as the map goes because the operator< in this case isn't defined in any special way, it's just a comparison between addresses. If you had used a std::string as key, they would have matched, though (because they do have their own operator<).
A few reasons for this behavior:
Sets are kept sorted as you input values, so s1 and s2 actually look the same if u print it out.
Sets have overloaded operators so that s1 == s2 compares the contents instead
the second example with *char explicitly put the pointer (address) as the key
declaring the static string gives u different addresses for two instances of "foo"
if you put s2 = s1 instead instead you should get the same behavior
looking at the documentation on cppreference.com:
template<
class Key,
class T,
class Compare = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T> >
> class map;
so if you don't supply your own custom comparison function, it orders the elements by the < operator, and:
operator==,!=,<,<=,>,>=(std::set)...
Compares the contents of lhs and rhs
lexicographically. The comparison is
performed by a function equivalent to
std::lexicographical_compare.
so when you call < on two sets it compares their sorted elements lexicographically. your two sets, when sorted, are exactly the same.
When you do:
cout << (s1 == s2);
You get an output of 1. I don't know how sets in C++ work; I don't even know what they are. I do know that the == comparison operator does not return whether not the values of the sets are in the same order. Likely, it returns whether or not the sets contain the same values, regardless of order.
Edit: Yeah, the sets are sorted. So when you create them, they get sorted, which means they become the same thing. Use a std::vector or a std::array
Edit #2: They do become equal. Let me create an analogy.
int v1 = 4 + 1;
int v2 = 1 + 4;
Now obviously, v1 and v2 would be the same value. Sets are no different; once created, the contents are sorted, and when you compare using the == operator, which is how partially how std::map identifies mapped elements, it returns "yes, they are equal". That is why your code works how it works.

What does iterator->second mean?

In C++, what is the type of a std::map<>::iterator?
We know that an object it of type std::map<A,B>::iterator has an overloaded operator -> which returns a std::pair<A,B>*, and that the std::pair<> has a first and second member.
But, what do these two members correspond to, and why do we have to access the value stored in the map as it->second?
I'm sure you know that a std::vector<X> stores a whole bunch of X objects, right? But if you have a std::map<X, Y>, what it actually stores is a whole bunch of std::pair<const X, Y>s. That's exactly what a map is - it pairs together the keys and the associated values.
When you iterate over a std::map, you're iterating over all of these std::pairs. When you dereference one of these iterators, you get a std::pair containing the key and its associated value.
std::map<std::string, int> m = /* fill it */;
auto it = m.begin();
Here, if you now do *it, you will get the the std::pair for the first element in the map.
Now the type std::pair gives you access to its elements through two members: first and second. So if you have a std::pair<X, Y> called p, p.first is an X object and p.second is a Y object.
So now you know that dereferencing a std::map iterator gives you a std::pair, you can then access its elements with first and second. For example, (*it).first will give you the key and (*it).second will give you the value. These are equivalent to it->first and it->second.
The type of the elements of an std::map (which is also the type of an expression obtained by dereferencing an iterator of that map) whose key is K and value is V is std::pair<const K, V> - the key is const to prevent you from interfering with the internal sorting of map values.
std::pair<> has two members named first and second (see here), with quite an intuitive meaning. Thus, given an iterator i to a certain map, the expression:
i->first
Which is equivalent to:
(*i).first
Refers to the first (const) element of the pair object pointed to by the iterator - i.e. it refers to a key in the map. Instead, the expression:
i->second
Which is equivalent to:
(*i).second
Refers to the second element of the pair - i.e. to the corresponding value in the map.
Used for map and unordered map.
map stores the key-value pair where i->first is for key and i->second is reflecting value.
#include<bits/stdc++.h>
#define long long int
using namespace std;
int32_t main(){
map<int,int> m;
m.insert({1,2});
m.insert({2,4});
for(auto i:m){
cout<<"key - "<<i.first<<" "<<" Value - "<<i.second<<endl;
}
}

Does boost::unordered_map return a reference or copy of value

When using a boost unordered_map, if I do map[key] will the type returned be a reference to the value V or a copy of the value?
Thanks
It is a reference, otherwise this wouldn't work:
map[key] = value;
According to the documentation, it would appear to be a reference.
mapped_type& operator[](key_type const& k);
From Boost documentation :
mapped_type& operator[](key_type const& k);
Effects:
If the container does not already contain an elements with a key equivalent to k, inserts the value std::pair(k, mapped_type())
Returns:
A reference to x.second where x is the element already in the container, or the newly inserted element with a key equivalent to k
Throws:
If an exception is thrown by an operation other than a call to hasher the function has no effect.
Notes:
Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.
Pointers and references to elements are never invalidated.
The accessor operator [] always returns a reference. The map element will be created if it doesn't exist. So to avoid repeated searches, the following pattern is useful:
std::unordered_map<K, T> m = populate_me();
T & value = m[key]; // created if non-existent
// use "value" rather than repeated "m[key]"

C++ template class map

I add the constructor and two functions to the class of my previous linked question C++ iterate through a template Map and I need help at this points:
What do you reckon this constructor does?
Adding one value at the beginning of map?
I see though in the respective key only an address as value after initializing in main. What is wrong?
The operator [] is supposed to get the values for a specific key. However I cannot use it so as to get the elements of the map in the output. Any hint?
template<class K, class V>
class template_map{
public:
template_map( V const& val) {
m_map.insert(my_map.begin(),std::make_pair(std::numeric_limits<K>::min(),val));
};
typedef typename std::map<K,V> TMap;
TMap my_map;
typedef typename TMap::const_iterator const_iterator;
const_iterator begin() const { return my_map.begin(); }
const_iterator end() const { return my_map.end(); }
V const& operator[]( K const& key ) const {
return ( --my_map.upper_bound(key) )->second;
}
...
};
int main()
{
interval_map<int,int> Map1 (10);
//Show the elements of the map?
}
Consider also that it should be a function that inserts values to the map.
What do you reckon this constructor does? Adding one value at the beginning of map?
It initialises the map so that map[x] == v for any x. The map associates intervals with values, internally storing a normal map keyed by the start of each interval; it's initialised so that the entire range of the key type maps to the initial value.
I see though in the respective key only an address as value after initializing in main. What is wrong? The operator [] is supposed to get the values for a specific key. However I cannot use it so as to get the elements of the map in the output. Any hint?
I've no idea what you're asking there. If you try, for example, cout << Map1[42] << '\n';, then your program should output 10, since that is the initial value assigned to the entire range of integers.
Consider also that it should be a function that inserts values to the map.
Since the internal map is publicly exposed, you can add a new interval to the map with
Map1.my_map.insert(std::make_pair(interval_start, value));
It might be more polite to make my_map private, and provide an insert() function to do that. You could also add a non-const overload of operator[] that inserts a new range and returns a reference to its value, something like
V & operator[](K const & key) {
V const & old_value = (--my_map.upper_bound(key))->second;
return *my_map.insert(std::make_pair(key, old_value)).first;
}
although this might not be a great idea, as you'd have to be careful that you don't accidentally insert many ranges when you only want to read the values.
My problem is how to iterate through the map to get all its elements and print them in main. It shows me an address with a value of the object initialization.
Remembering that an iterator over a map refers to a key/value pair (of type std::pair<K,V>), you should be able to iterator over the map like this:
for (auto it = Map1.begin(); it != Map1.end(); ++it) {
std::cout << it->first << " maps to " << it->second << '\n';
}
(in C++03, you'll need to write template_map<int,int>::const_iterator rather than auto).
What do you reckon this constructor does? Adding one value at the
beginning of map? I see though in the respective key only an address
as value after initializing in main. What is wrong?
It adds this one value in to the map. The iterator argument is only a hint: if the new item is to be inserted right after this position, the operation can be completed faster. Otherwise the map will need to find the right place to insert the new value as usual.
The operator [] is supposed to get the values for a specific key.
However I cannot use it so as to get the elements of the map in the
output. Any hint?
upper_bound returns iterator to the first key-value pair, where key is greater than the argument. --upper_bound therefore returns an iterator to the item, whose key is either equal or less than the queried key. If upper_bound returned map.begin(), because all keys are greater than the query, decrementing it is undefined behavior.
What you need here is the find member function. You also need to deal with the case the key is not found (map.end() is returned), e.g by throwing an exception.
Alternatively you may implement your operator[] in terms of map::operator[]. This means that the function can't be const, because map inserts a new default value if the key is not found.
The iterator in map::insert() is just a hint; essentially it doesn't mean anything in terms of the semantics of the program.
Your code inserts the value passed through the constructor argument together with the key numeric_limits<K>::min(), i.e. the smallest possible value for the given key type. This will only complile if numeric_limits is specialized for the type K.
Also note that if the key already exists, the corresponding mapped value will not be overwritten, so a corresponding insert function would be of very limited use.