17

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
Vlad Davidchenko
  • 454
  • 1
  • 7
  • 24
Gaurav Srivastava
  • 505
  • 1
  • 7
  • 17
  • This is definitely something I've noticed as well. gdb seems to have problems resolving overloaded operators, and it frequently can't find the definition of commonly used functions – Justin Sep 13 '17 at 19:47
  • 1
    Possibly relevant https://stackoverflow.com/questions/34894381/python-pretty-printing-with-gdb-does-not-support-maps-indexing-operator - and look up other answers on prettyprinting. –  Sep 13 '17 at 19:54
  • 4
    gdb isn't a C++ compiler, so while it does know a lot of C++, it does not have all the C++ rules built in (In this case it seems it cant figure it should create a std::string temporary object from a string literal and then resolve the proper overload of the map) – nos Sep 13 '17 at 19:58
  • Thanks for the replies. Based on the comments, I should not try to operator [] with unordered_map. Instead, I could print all the members of the map using print mymap in gdb. – Gaurav Srivastava Sep 13 '17 at 22:46
  • Related https://stackoverflow.com/q/427589/72178. – ks1322 Sep 14 '17 at 08:38
  • Possible duplicate of [Inspecting standard container (std::map) contents with gdb](https://stackoverflow.com/questions/427589/inspecting-standard-container-stdmap-contents-with-gdb) – sandwood Mar 26 '18 at 13:01
  • There is a 'most expressive' option -ggdb as described in the documentation of gcc. Also there is an optimization for debugging -Og – anakin Apr 07 '18 at 22:55
  • See also: https://stackoverflow.com/questions/7429462/creating-c-string-in-gdb – John Zwinck Jun 25 '18 at 13:44

1 Answers1

11

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.

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33
  • It's possible to create a `std::string` in gdb. Refer to [this post](https://stackoverflow.com/a/11311786/4123703) – Louis Go Feb 21 '23 at 03:29
  • @LouisGo thanks. The solution in that post just shows how much C++ support in GDB is broken. It never crossed my mind to go that close to the metal, for such a simple thing as creating a string in GDB. Moreover, I didn't know that GDB mandated the usage of a syntax which is forbidden in C++. In C++, when you want to call the constructor, it is illegal to use the method-call syntax, like the post suggests. – Michael Veksler Feb 22 '23 at 12:29