6

I am debugging some C++ code and I have a really large std::vector<floating_point_type> (float or double). In C++ code when I want the max value of the std::vector I can just use std::max_element(). So in gdb I tried to use the same code, but I got an error.

In gdb I used call std::max_element(x) and got an error message No symbol "max_element" in namespace "std".

Is there any way to get the max value of a vector in gdb?

I would also appreciate an explanation for why my attempt at using std::max_element was not working (perhaps std::max_element a header-only or inline function).

Trevor Boyd Smith
  • 18,164
  • 32
  • 127
  • 177
  • 4
    `std::max_element()` is a template function so I am afraid gdb is not clever enough to instantiate it on the fly. – Slava Jun 18 '18 at 13:28
  • 1
    Gdb lets you write functions (in it's own scripting language or python) that you can call to display your vector: they can trivially iterate the elements to find a maximum then display that. [this answer](https://stackoverflow.com/a/25499805/410767) should help you get started. – Tony Delroy Jun 18 '18 at 13:52
  • @TonyDelroy i purposely wrote the question open ended because i was thinking of writing my own for loop to find the max element. your comment could easily be a solution (whether in gdb language or python language.) – Trevor Boyd Smith Jun 18 '18 at 16:59

3 Answers3

14

std::max_element is a function template, not a function. You are asking GDB to do template argument deduction and the whole shebang involved with calling a template function without specifying arguments. It can't do that, naturally, it's not a full fledged compiler.

As far as I know any solution, from the simplest to the most complex, will require of you to modify your source in such a way that std::max_element is instantiated for the iterator types of your vector. So you may as well add "debug only" code that computes the maximum element and stores it into a local variable.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • for most cases, i think compiling/instantiating a "debug only" function is the most straight forward solution to get access to `std::max_element` from `gdb`. for some minority cases, i think @n.m. has a good solution (although for my eyes @n.m.'s looks difficult/very-complex (his solution probably only seems difficult to me because I'm a newbie at C++ with only 17+ years experience)). – Trevor Boyd Smith Jun 19 '18 at 13:27
  • [here is some good example code that someone created after your solution to demonstrate what you are describing](https://stackoverflow.com/a/50912371/52074). – Trevor Boyd Smith Jun 19 '18 at 13:28
  • @TrevorBoydSmith - Well. To be fair, n.m.'s solution is "the most complex solution" I had in mind. It just brilliantly manages to avoid restarting the debugging session. – StoryTeller - Unslander Monica Jun 19 '18 at 13:29
6
(gdb) p std::max⭾⭾⭾

(No response from gdb)

 (gdb) p std::max_element(v.begin(), v.end())
 No symbol "max_element" in namespace "std".

Here is how to call an uninstantiated function template from gdb without breaking your session and recompiling your program.

  1. Open an editor and create a C++ source file with an explicit instantiation of the needed function. For example:

    // /tmp/tmpsource.cpp
    #include <algorithm>
    #include <vector>
    using T = std::vector<int>::iterator;
    template T std::max_element<T>(T, T);
    

    This can probably be automated somehow with a shell script. Give it a name of a function and template arguments, and it will generate you a complete buildable C++ source. Probably not worth the trouble though.

  2. Build a shared library/DLL from the source.

    g++ -fPIC -shared -ggdb -O0 -o /tmp/libtmpsource.so /tmp/tmpsource.cpp
    
  3. Load the library in your debugging session.

    load /tmp/libtmpsource.so
    # if this doesn't work
    p dlopen("/tmp/libtmpsource.so", 2)
    # or perhaps even
    p LoadLibraryA("c:/temp/libtmpsource.so")
    
  4. Let's try the function now.

    (gdb) p std::max_element(v.begin(), v.end())
    No symbol "max_element" in namespace "std".
    
  5. What? No worries, everything is under control. gdb is not a C++ compiler and it cannot do the template deduction thing. You need to specify your <...> yourself. Fortunately, autocompletion works (sometimes).

    (gdb) p std::max⭾
    (gdb) p std::max_element<__gnu_cxx::__normal_iterator<int*, std::vector<int, 
     std::allocator<int> > > >(__gnu_cxx::__normal_iterator<int*, std::vector<int, 
     std::allocator<int> > >, __gnu_cxx::__normal_iterator<int*, std::vector<int, 
     std::allocator<int> > >)
    
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
3

As std::max_elemente is a function template, you can not use it directly in gdb. What you can do, create a wrapper over it.

float my_max_element(std::vector<float>& vec) 
{
    return *(std::max_element(vec.begin(), vec.end());
}

Now you can call my_max_element in gdb.

SaurabhS
  • 633
  • 1
  • 7
  • 18