Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using [] operator with unordered_map in gdb give unresolved operator

I have a C++ code where I am instantiating an unordered_map and then printing it's values using cout. This works fine. But, when I try to run this in gdb and print the values of the unordered_map, this gives me error. Below, is the code snippet:

  std::unordered_map<std::string,int> mymap = {
                      { "Mars", 3000},
                      { "Saturn", 60000},
                      { "Jupiter", 70000 } };

    std::cout<< mymap.at("Mars");
    std::cout<< mymap["Mars"];

Both the cout statements above print the unordered_map value for key "Mars". However, when I use gdb and then try using below statements to print the value of mymap at key "Mars", I get errors.

(gdb) print mymap.at("Mars")
Cannot resolve method std::unordered_map<std::basic_string<char, 
std::char_traits<char>, std::allocator<char> >, int, 
std::hash<std::basic_string<char, std::char_traits<char>, 
std::allocator<char> > >, std::equal_to<std::basic_string<char, 
std::char_traits<char>, std::allocator<char> > >, 
std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, 
std::allocator<char> > const, int> > >::at to any overloaded instance

(gdb) print mymap["Mars"]
Cannot resolve function operator[] to any overloaded instance

I do not get what is wrong when I use gdb.

I have tried using whatis mymap, in gdb, to see if mymap is present in current context and it gives that it is present. Also, I tried initializing an int variable and printing it in gdb and it prints it. I do not understand what is the problem with unordered_map.

I am using below statement to generate executable

gsrivas4@TitanX01:~/lcode1$ g++ -std=gnu++11 -O0 -g test1.cpp -o test1.out
like image 657
Gaurav Srivastava Avatar asked Sep 13 '17 19:09

Gaurav Srivastava


People also ask

How do you check if an element is in an unordered_map?

To check for the existence of a particular key in the map, the standard solution is to use the public member function find() of the ordered or the unordered map container, which returns an iterator to the key-value pair if the specified key is found, or iterator to the end of the container if the specified key is not ...

Can you iterate through unordered_map?

Iterating over a map by using STL Iterator: By creating an iterator of std::map and initializing it to the starting of map and visiting upto the end of map we can successfully iterate over all the elements of map.

Can unordered map have same keys?

Because unordered_map containers do not allow for duplicate keys, this means that the function actually returns 1 if an element with that key exists in the container, and zero otherwise.

Why do you use unordered_map why not ordered map?

map is used to store elements as key,value pairs in sorted order. unordered_map is used to store elements as key,value pairs in non-sorted order.


1 Answers

The problem you are facing is that std::unordered_map<std::string,int>::at(key) expects a key of type std::string, not a const char* literal. This means that you'd like to create a temporary std::string object, before passing it to at().

Creating a temporary object from within GDB does not work well for me, and I may be missing something but this is what I get:

(gdb) p std::string("Mars")
A syntax error in expression, near `"Mars")'.
(gdb) p 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)'("Mars")
$9 = -161888904

So it does not seem possible to construct an std::string object inside GDB without some additional C++ code, so just add to your C++ code:

std::string make_string(const char *x)
{
        return x;
}

And now everything works:

(gdb) p mymap.at(make_string("Mars"))
$1 = (std::unordered_map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::hash<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::mapped_type &) @0x60005e5f0: 3000
(gdb) p mymap.at(make_string("Jupiter"))
[New Thread 14608.0x16f4]
$2 = (std::unordered_map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, std::hash<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >::mapped_type &) @0x60005e650: 70000

But

(gdb) p mymap[make_string("Jupiter")]
Could not find operator[].

This does not work because it was never instantiated. What your code instantiated by:

std::cout<< mymap["Mars"];

was T& operator[]( Key&& key ); which is tricky to invoke from GDB. Had you instantiated T& operator[]( const Key& key ); instead, then things would have fared better.

The solution: instantiate the operator[](const std::string &) variant in your C++ code. So here is the new code:

std::string make_string(const char *x)
{
        return x;
}

int main()
{
 std::unordered_map<std::string,int> mymap = {
                      { "Mars", 3000},
                      { "Saturn", 60000},
                      { "Jupiter", 70000 } };

    std::string mars{"Mars"};
    std::cout<< mymap.at(mars);
    std::cout<< mymap[mars];
}

With this, debugging becomes possible:

print mymap.at(make_string("Jupiter"))
print mymap[make_string("Jupiter")]

just work.

like image 94
Michael Veksler Avatar answered Sep 22 '22 08:09

Michael Veksler