C++ template class map - c++

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.

Related

why are these two ways of accessing parts of C++ map pairs different

I was puzzled when I received an error that suggested I use a . operator to access the value in a pair from a map because when I changed it in two places in code I received a new error that suggested that I use a -> in the second place in code. I listened to the naggy compiler. Why did I need to?
Here's what I was doing:
In a range based for loop, I want the value from the key-value pair which could be exampled:
std::map<std::string, aclass> mapthings;
...
for (auto& it : mapthings) {
fout << it.second.stringify();
}
I'm also using the same mapthings but using the find() function:
return (mapthings.find(name))->second;
Because find return mapthings::iterator,which stores a pointer to mapthings::value_type.
While auto& it is a object of mapthings::value_type.
In the first example range-based for loop gives object directly. So you can use ..
In the second example find gives you iterator to the object. That compels you to use -> because you need object itself.
In this code snippet
std::map<std::string, aclass> mapthings;
...
for (auto& it : mapthings) {
fout << it.second.stringify();
}
it is of type value_type of std::map<std::string, aclass> that corresponds to type
std::pair<const std::string, aclass>
So to access members of an object of this type you have to use operator .
In this code snippet
return (mapthings.find(name))->second;
method find returns iterator that points to the target record of the map or to iterator returned by end(). Iterators are like pointers. So you need to use operator -> to access members of the pointed object.
Take into account that you could write simpler
return mapthings.find( name )->second;
or
return ( *mapthings.find( name ) ).second;
When you use this code, you get a reference to a std::pair containing your data
for (auto& it : mapthings) {
fout << it.second.stringify();
}
In the second example, find returns an iterator which needs to be dereferenced to be read
In the first one, you get a std::map::value_type&, which is defined to be std::pair<const Key, T>. This method is best for accessing all the members of the map.
In the second one, you get a std::map::iterator. std::map::iterator has operator-> overloaded, which returns a std::map::value_type*. This method is best for find, upper_bound, lower_bound, etc. since you are performing queries on the map. The map might not hold a member corresponding to the key used in the query.

Changing Assigned Value for STL Map [duplicate]

This question already has answers here:
std::map default value
(16 answers)
Closed 8 years ago.
As I create a std::map, all the indexes are initially pointing nowhere. As soon as I call them, they allocated and assigned the value 0.
For example:
map <int, int> x;
cout << x.[31233];
The output is 0.
However, I need that all the standard assigned value to be (-1) instead of 0.
How can I change this?
After this definition
map <int, int> x;
the map has no elements. To add an element with key 31233 and value -1 you can write
x[31233] = -1;
You can not do such a way that the default value would be -1 because according to the C++ Standard relative to the subscript operator
If there is no key equivalent to x in the map, inserts value_type(x, T()) into the map
For type int int() zero initializes the corresponding object.
Otherwise you should use some insert method where you will explicitly specify an initial value.
Given a std::map<key_type, value_type>, a lookup for an arbitrary key through operator [](cont key_type&) will auto-insert value_type() for said-key if it wasn't present. In your case, value_type is int, and int() is zero-initialized, therefore zero is the result.
if you want to use a different default construct, you have options, the most extreme of which would be writing a custom allocator specialized for int and a construct member to us -1 for int value types (yuck). I think you may find it easier to simply:
std::map <int, int> x;
// load map with values...
int res = -1;
auto it = x.find(31233);
if (it != x.end())
res = x.second;
// use res here.
You should simply stop using the operator[] and instead use insert() when you intend to insert a new value. If you want to have a "default" value for things that have never been inserted, it may be better to write your own container which uses a map internally and exposes something like a get() method which returns the stored value from the map or -1 if not found. That way you avoid storing lots of -1 values that aren't needed.

which element will be returned from std::multimap::find, and similarly std::multiset::find?

Most likely this question is a duplicate but I could not find a reference to it.
I'm looking at std::multiset::find & std::multimap::find functions and I was wondering which element will be returned if a specific key was inserted multiple times?
From the description:
Notice that this function returns an iterator to a single element (of
the possibly multiple equivalent elements)
Question
Is it guaranteed that the single element is the first one inserted or is it random?
Background
The reason I'm asking is that I'm implementing multipmap like class:
typedef std::vector<Item> Item_vector;
class Item
{
string m_name;
};
class MyItemMultiMap
{
public:
// forgive me for not checking if key exist in the map. it is just an example.
void add_item( const Item& v ) { m_map[v.m_name].push_back(v); }
// is returning the first item in the vector mimic std::multimap::find behavior?
Item& get_item( const string& v ) { return m_map[v][0]; }
private:
std::map<string,Item_vector> m_map;
};
I'd like get_item() to work exactly as std::multimap::find. is it possible? if so, how would it be implemented?
The find method may return an arbitrary one if more than one is present, though your STL implementation might indeed just give the first one.
It's safer to use the 'lower_bound' method, and ++ iterate from there (see std::multimap::lower_bound). Do note though that 'lower_bound' returns a ref to another element if what you're looking for isn't present!
The C++ standard says that for any associative container a, a.find(k) "returns an iterator pointing to an element with the key equivalent to k, or a.end() if such an element is not found", and it doesn't impose any additional requirements on multimap. Since it doesn't specify which element is returned, the implementation is permitted to return any matching element.
If you're trying to imitate the exact behavior of multimap on the platform where you're running, that's bad news, but if your goal is just to satisfy the same requirements as multimap, it's good news: you can return any matching element that you want to, and in particular it's fine to just always return the first one.
http://en.cppreference.com/w/cpp/container/multimap/find
Finds an element with key key. If there are several elements with key
in the container, the one inserted earlier is selected.
So, an iterator to the first element will be returned.
In general, I find equal_range to be the more useful method, returning a pair of iterators pointing respectively at the first, and after the last, elements matching the key.

is insert() necessary in a map or unordered_map?

I see a lot of examples that add items to a map or unordered_map via operator[], like so:
int main() {
unordered_map <string, int> m;
m["foo"] = 42;
cout << m["foo"] << endl;
}
Is there any reason to use the insert member function instead? It would appear they both do the same thing.
They are not.
operator[] will overwrite the value for this key, if it exists, while insert will not.
In case operator[] is used for inserting element, it is expected to be a little slower (see #MatthieuM's comment below for details), but this is not that significant here.
While std::map::insert returns std::pair< iterator, bool >, where the .second will tell you if the value is inserted or it already exists.
Regarding your comment: you cannot have 2 elements with the same key and different value. This is not a multimap.
If there's an element in the map, with the same key you're trying to insert, then:
operator[] will overwrite the existing value
std::map::insert will not do anything.* return a std::pair< iterator, bool >, where the .second will be false (saying "the new element is not inserted, as such key already exists") and the .first will point to the found element.
* I changed this thanks to the note/remark, given from #luk32; but by writing "will not do anything", I didn't mean it literally, I meant that it will not change the value of the existing element
Using insert() can help improve performance in certain situations (more specifically for std::map since search time is O(log(n)) instead of constant amortized). Take the following common example:
std::map<int, int> stuff;
// stuff is populated, possibly large:
auto iterator = stuff.find(27);
if(stuff.end() != iterator)
{
// subsequent "find", set to 15
iterator->second = 15;
}
else
{
// insert with value of 10
stuff[27] = 10;
}
The code above resulted in effectively finding the element twice. We can make that (slightly) more efficient written like this:
// try to insert 27 -> 10
auto result = stuff.insert(std::make_pair(27, 10));
// already existed
if(false == result.second)
{
// update to 15, already exists
result.first->second = 15;
}
The code above only tries to find an element once, reducing algorithmic complexity. For frequent operations, this can improve performance drastically.
The two are not equivalent. insert will not overwrite an existing value, and it returns a pair<iterator, bool>, where iterator is the location of the key, regardless of whether or not it already existed. The bool indicates whether or not the insert occurred.
operator[] effectively does a lower_bound on key. If the result of that operation is an iterator with the same key, it returns a reference to the value. If not, it inserts a new node with a default-constructed value, and then returns a reference to the value. This is why operator[] is a non-const member - it auto-vivifies the key-value if it doesn't exist. This may have performance implications if the value type is costly to construct.
Also note in C++11, we have an emplace method that works nearly identical to insert, except it constructs the key-value pair in-place from forwarded arguments, if an insert occurs.
Well I disagree with Kiril's answer to a certain degree and I think it's not full so I give mine.
According to cppreference std::map::operator[] is equivalent to a certain insert() call. By this I also think he is wrong saying the value will be overwritten.
It says: "Return value
Reference to the mapped value of the new element if no element with key key existed. Otherwise a reference to the mapped value of the existing element is returned."
So it seems it is a convenient wrapper. The insert(), however has this advantage of being overloaded, so it provides more functionality under one name.
I give a point to Kiril, that they do seem to have a bit different functionality at first glance, however IHMO the examples he provides are not equivalent to each other.
Therefore, as an example/reason to use insert I would point out, inserting many elements at once, or using hint ( Calls 3-6 in here).
So is insert() necessary in a map or unordered_map?
I would say yes. Moreover, the operator[] is not necessary as it can be emulated/implemented using insert, while the other way is impossible! It simply provides more functinality. However, writing stuff like (insert(std::make_pair(key, T())).first)->second) (after cppreference) seems cumbersome than [].
Thus, is there any reason to use the insert member function instead?
I'd say for overlapping functionality, hell no.

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;
}
}