Delete value from unordered-map with 3 elements - c++

Here is an MWE for the unordered map that I'm using. Based on what I understood here, the public member function "erase" is used to erase the elements from the unordered map.
#include <iostream>
#include <string>
#include <algorithm>
#include <unordered_map>
using namespace std;
int main() {
std::unordered_map<int, std::pair<int, int> > m;
m.insert({3, std::make_pair(1,1)});
m.insert({4, std::make_pair(5,1)});
cout << m[4].first << endl;
m.erase(4);
cout << m[4].first << endl;
}
However, what I see from this example is as follows:
5
0
I was expecting only 5 and then throw an error that the key doesn't exist.
What am I missing?

As pointed out in the documentation, if a value does not exist in an unordered_map, operator[] will introduce a new element with the corresponding key. What you get back in the second query is the default-constructed pair, constructed by operator[].
As #you pointed out in his comment, you can instead use at() which includes a "range" check and throws an std::out_of_range exception if the key is now in the unordered_map.
If you want to avoid the exception, you can first check if m.find(4)==m.end(), which indicates that the key 4 is not in the map, as pointed out by #YSC in his comment.

Related

What's 'mymap[1];' instruction where mymap is std::map?

I found a code which use the instruction mymap[1];. Did any one know the meaning of it?
Here is a sample code which compiles successfully:
#include <iostream>
#include <map>
using namespace std;
int main()
{
std::map<int,int> mymap;
mymap[1];
cout<<mymap[1];
return 0;
}
mymap[1] gives you the element with the key 1. For example, you could assign to it: mymap[1] = something;, or print it: std::cout << mymap[1];.
If the element is missing, it's inserted automatically. The new element is value-initialized, which for scalar types essentially means zeroed.
As you noticed, doing just mymap[1]; is allowed. It inserts the element if it's missing, and does nothing else.

how to assign to element of set of pairs through find iterator result

I have a set of pairs and I want to change the second field of some pair that I want find first:
#include <iostream>
#include <utility>
#include <set>
int main(){
auto p=std::make_pair(2,3);
std::set<std::pair<int,int>> s{p};
auto it=s.find(p);
it->second=5; // compilation error
if(it!=s.end()) std::cout << it->second << '\n';
}
The above code fails to compile because it complains that the iterator result of find cannot be assigned to. However, I don't see why it is a const iterator.
What is wrong with the above, and how do I assign to the pair that the iterator result of find points to?
It's because set elements shouldn't be mutable, since the red-black tree that is used to implement it logically prevents us from screwing around with the actual nodes. Even without the implementation details, set elements shouldn't be mutable (as pointed out in one of the comments above), or else we could change {2,3} to {2,2}, which would be nonsensical.

How to initialize the key field of a map with the use of an iterator?

#include <iostream>
#include <map>
#include <string>
int main ()
{
std::string s;
std::cout<<" String : ";
std::getline(std::cin,s);
std::map<std::string,std::string> mapa;
std::map<std::string,std::string>::iterator it(mapa.begin());
it->first = s;
it->second = s;
std::cout << it->second << std::endl;
return 0;
}
Why can I not initialize the key field of a map (it->first=s does not work) but the second field does work?. And what is the solution?
Why can I not initialize the key field of a map (it->first=s does not
work) but the second field does work?. And what is the solution?
You have the answer in your question itself. std::map maps a key to a value. That means, at the time of creation itself you need to set both(key and value).
it->first=s; This will not compile, because you haven't mentioned, what is the key for.
it->second=s; This is a UB. Since you haven't mentioned the key with it.
std::map is a sorted associative container that contains key-value
pairs with unique keys. Keys are sorted by using the comparison
function Compare.
Therefore, in order to do the comparison and put in the correct position in the data structure, it needs both informations together.
The solutions are:
mapa[key] = value; using (operator[]). You can use the same to access the values in the map directly by their corresponding key.
mapa.emplace("key", "value");
mapa.insert ( std::pair<std::string, std::string>("key", "value") );
mapa.insert ( std::make_pair("key", "value") );
std::map<std::string,std::string>::iterator it(mapa.begin());
mapa.insert (it, std::pair<std::string, std::string>("key", "value"));

Comparing unordered_map vs unordered_set

First of all, what is the main difference between them?
The only thing i've found is that unordered_set has no operator [].
How should i access an element in unordered_set, since there is no []?
Which container is using random access to memory(or both)?
And which one of them faster in any sense or using less memory?
They are nearly identical. unordered_set only contains keys, and no values. There is no mapping from a key to a value, so no need for an operator[]. unordered_map maps a key to a value.
You can use the various find methods within unordered_set to locate things.
you can use iterators to access elements.
unordered_set <string> u{
"Dog",
"Cat",
"Rat",
"Parrot",
"bee"
};
for(auto& s:u){
cout << s << ' ';
}
unordered_set<string>::const_iterator point = u.find("bee");
How should I access an element in unordered_set (C++17)?
In C++ 17 a new function extract is added to unordered_set.
Specially, this is the only way to take move only object out of the set.
https://en.cppreference.com/w/cpp/container/unordered_set/extract
For example if you want third element of your unordered set.
Advance the iterator
std::advance(it,2);
Then extarct the value
s.extract(it).value();
Here is the complete code. try on any C++17 compiler.
#include <iostream>
#include <string>
#include <unordered_set>
#include <iterator>
int main()
{
//CREATE AN OBJECT
std::unordered_set<std::string> s;
//INSERT DATA
s.insert("aee");
s.insert("bee");
s.insert("cee");
s.insert("dee");
//NEED TO INCLUDE "iterator" HEADER TO USE "std::advance"
auto it = s.begin();
std::advance(it,2);
//USING EXTRACT
std::string sval = s.extract(it).value();
std::cout<<sval;
}
Note: if queried for out of bound index, nothing happens. No result.
Try changing your code
//ONLY FOUR ELEMENTS
std::advance(it,8);
//USING EXTRACT
std::string sval = s.extract(it).value();

How do you use a range-based for loop on the values of a std::map?

I'm trying to use std::map::operator[] to iterate over the values of a std::map with a range-based for loop, but the following doesn't compile:
#include <iostream> // cout, endl
#include <map> // map
#include <set> // set
using namespace std;
int main () {
using namespace std;
const map<int, set<int>> m {{2, {201, 202}}, {3, {301, 302}}};
for (int v : m[2])
cout << v << endl;
return 0;
}
Here's the compiler's error message:
Test.c++:18:19: error: no viable overloaded operator[] for type 'const map<int, set<int> >'
for (int v : m[2])
The followup question is, Given that there are two versions of at(), why aren't there two versions of []?
map::operator[] inserts a new element into the map if the key isn't found, hence it cannot be const, and cannot be called on a const map.
Use m.at(2) instead.
operator[] will do one of two things. It will find the element at that location if it exists and return it. If there is no element at that location, it will value-initialize it, and then return it.
As such, it is neither logically nor programmatically const.
While you may say "but there is an element 2", the constness of an operation depends only on the types of the arguments, not the value of the arguments. And m[int] isn't guaranteed to have a valid element there.
To fix this, you can replace m[2] with m.find(2)->second. This does undefined behavior if 2 is missing from the map, but if 2 is present it will evaluate to the same thing as m[2]. Alterantively, m.at(2) will again do the same thing if 2 is present as a key, and throw an exception if is not present.
As an aside, when working on such a problem, try breaking your code down into smaller pieces. m[2]; all by itself on a line will fail to compile. In fact, the error message told you that it could not find an operator[] -- that might have given you a clue what was wrong.
Your map m is declared const meaning that you can only call const functions on it.
std:map::operator[] is not a such function, since it will modify the map if the specified key is not found.
What you need is std::map::at, which is const so you can call it on your const map.