【问题标题】:gdb: how do you get the max value of a std::vector<float>?gdb:如何获得 std::vector<float> 的最大值?
【发布时间】:2018-11-27 08:41:30
【问题描述】:

我正在调试一些 C++ 代码,我有一个非常大的 std::vector&lt;floating_point_type&gt;floatdouble)。在 C++ 代码中,当我想要 std::vector 的最大值时,我可以使用 std::max_element()。所以在gdb我尝试使用相同的代码,但我得到了一个错误。

gdb 我使用call std::max_element(x) 并收到错误消息No symbol "max_element" in namespace "std".

有什么办法可以得到gdb中向量的最大值?

如果我尝试使用 std::max_element 不起作用(可能是 std::max_element 仅标头或内联函数),我也将不胜感激。

【问题讨论】:

  • std::max_element() 是一个模板函数,所以恐怕 gdb 不够聪明,无法即时实例化它。
  • Gdb 允许您编写函数(在它自己的脚本语言或 python 中),您可以调用这些函数来显示您的向量:它们可以简单地迭代元素以找到最大值然后显示它。 this answer 应该可以帮助您入门。
  • @TonyDelroy 我故意写了开放式问题,因为我正在考虑编写自己的 for 循环来查找最大元素。您的评论很容易成为解决方案(无论是 gdb 语言还是 python 语言。)

标签: c++ vector gdb


【解决方案1】:
(gdb) p std::max⭾⭾⭾

(gdb 没有响应)

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

这里是如何在不中断会话和重新编译程序的情况下从 gdb 调用未实例化的函数模板。

  1. 打开一个编辑器并创建一个带有所需函数的显式实例化的 C++ 源文件。例如:

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

    这可能可以通过 shell 脚本以某种方式自动化。给它一个函数名和模板参数,它会为你生成一个完整的可构建的 C++ 源代码。不过可能不值得麻烦。

  2. 从源代码构建共享库/DLL。

    g++ -fPIC -shared -ggdb -O0 -o /tmp/libtmpsource.so /tmp/tmpsource.cpp
    
  3. 在调试会话中加载库。

    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. 我们现在试试这个功能。

    (gdb) p std::max_element(v.begin(), v.end())
    No symbol "max_element" in namespace "std".
    
  5. 什么?不用担心,一切都在掌控之中。 gdb 不是 C++ 编译器,它不能做模板推导的事情。您需要自己指定&lt;...&gt;。幸运的是,自动完成功能(有时)有效。

    (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> > >)
    

【讨论】:

  • 猜我错了。有一个足够复杂的解决方案,不涉及更改调试会话的源代码:D +1
  • 开始阅读...开始讨论“只需打开编辑器,编译,然后转到 gdb 并加载共享对象库。大笑
  • 开始阅读您需要指定模板参数的部分,因为 gdb 无法扣除... 读取可怕的长模板参数。大声笑出来。
  • @TrevorBoydSmith 是的,它们非常长,但至少 gdb 为您完成了它们。
  • @TrevorBoydSmith 如果您在 100 多个小时的时间里追逐一个难以捉摸的 bug 之后发现必须离开 gdb 并重新编译,您还会笑吗?
【解决方案2】:

由于 std::max_elemente 是一个函数模板,你不能直接在 gdb 中使用它。 你可以做什么,在它上面创建一个包装器。

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

现在您可以在 gdb 中调用 my_max_element。

【讨论】:

    【解决方案3】:

    std::max_element 是函数模板,而不是函数。您要求 GDB 进行模板参数推导,以及在不指定参数的情况下调用模板函数所涉及的整个 shebang。它不能那样做,自然它不是一个成熟的编译器。

    据我所知,从最简单到最复杂的任何解决方案都需要您修改源代码,以便为向量的迭代器类型实例化 std::max_element。因此,您不妨添加“仅调试”代码来计算最大元素并将其存储到局部变量中。

    【讨论】:

    • 对于大多数情况,我认为编译/实例化“仅调试”功能是从gdb 访问std::max_element 的最直接的解决方案。对于一些少数情况,我认为@n.m。有一个很好的解决方案(尽管在我看来@n.m. 看起来很难/非常复杂(他的解决方案可能对我来说似乎很难,因为我是 C++ 的新手,只有 17 年以上的经验)。
    • @TrevorBoydSmith - 好吧。公平地说,n.m. 的解决方案是我想到的“最复杂的解决方案”。它只是巧妙地避免重新启动调试会话。
    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 2021-04-12
    • 2019-02-05
    • 1970-01-01
    • 2019-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多