c++11 - 在 gdb 中调用 std::~basic_string()

标签 c++11 gdb type-conversion destructor stdstring

根据@EvanED https://stackoverflow.com/a/11311786/890753我创建了一个 gdb 命令 newstr 来创建一个新的 std::string 并将其放入 gdb 便利变量中:

define newstr
set ($arg0)=(std::string*)malloc(sizeof(std::string))
call ($arg0)->basic_string()
# 'assign' returns *this; casting return to void avoids printing of the struct.
call (void)( ($arg0)->assign($arg1) )
end

效果很好:

(gdb) newstr $foo "hello world"
(gdb) p $foo->c_str()
$57 = 0xb22e388 "hello world"

我在其他自定义 gdb 命令中使用 newstr,因此为了整洁,我还创建了 delstr:

define delstr
call ($arg0)->~basic_string($arg0)
call free($arg0)
set ($arg0)=(void*)0
end

它可以工作,但是析构函数调用会产生一条恼人的消息:

(gdb) delstr $foo
warning: Using non-standard conversion to match method std::string::~basic_string to supplied arguments
$62 = 0

我可以避免“非标准转换”消息吗? (我使用的是 gdb 7.10。)

最佳答案

TL;DR:将 0 传递给析构函数,而不是 $foo

define delstr
call ($arg0)->~basic_string(0)
#                           ^
call free($arg0)
set ($arg0)=(void*)0
end

好吧,到底发生了什么...我们可以首先检查析构函数的签名。它确实需要一个整数:

(gdb) p ((Foo*) 0)->~Foo
$1 = {void (Foo * const, int)} 0x555555554c00 <Foo::~Foo()>

(gdb) p (('std::__cxx11::string'*) 0)->~basic_string
$2 = {void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > * const, int)} 0x7ffff7b75010 <std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()>

(gdb) ptype Foo
type = struct Foo {
  public:
    Foo(void);
    ~Foo(int);
}

所以“非标准转换”警告是关于将指针转换为整数,这确实是非标准的。 (该警告与析构函数无关。)

但是出于什么深刻的原因,我们首先需要向析构函数传递一个额外的整数呢?原来是……a bug 😃 实际上是一个 GCC 问题(从 gcc 6.3.0 开始),因为使用 clang 编译的同一程序(从 clang 3.8.1 开始)没有那个额外的 int 参数。


应该知道,在 Italium C++ ABI 中实际上有 three destructors (D0, D1, D2)。

GCC 有一个optimization -fdeclone-ctor-dtor它将三个析构函数的公共(public)部分重构为 "D4" destructor 。这个“D4”析构函数需要 an extra argument __in_chrg判断D0/D1/D2中哪一个是源,从而知道是否调用虚基析构函数。

这个“D4”析构函数在某种程度上也被用作 GCC 生成的 DWARF 符号的规范析构函数声明。如果我们检查GCC issue从 GDB bug 报告链接来看,使用“D4”的原因是 GCC 开发人员不想选择 D0、D1 或 D2 中的哪一个来祝福。

结果是一个额外的 int,GDB 没有忽略它。

当析构函数能够“完全销毁对象”(D0、D1)时,__in_chrg 值为 2,当析构函数能够“完全销毁对象”时,__in_chrg 值为 0。只是一个“基本对象析构函数”(D2)。由于 std::string 没有虚拟基类,因此您应该将 0 传递给该参数。


注意:我使用这个程序来测试 GDB:

#include <string>
#include <iostream>
std::string aa;
struct Foo {
        Foo() { std::cout << "Constructing: this = " << this << std::endl; }
        ~Foo() { std::cout << "Destroying: this = " << this << std::endl; }
};
int main() {
        Foo foo;
        return 0;
}

关于c++11 - 在 gdb 中调用 std::~basic_string(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42462860/

相关文章:

gcc - arm-none-eabi-gdb 和 openocd : Malformed response to offset query, qOffsets?

Java 货币面额舍入问题

c# - 复制 C# DataTable 并将所有值转换为字符串

windows - 我可以在 Windows 上使用 std::thread 吗?

c++ - 如何正确地释放指向对的指针列表?

c++ - 根据编译时参数使方法可用

debugging - GDB If语句返回值?

使用KGDB远程调试Linux内核: GDB does not recognize functions?

sql - 将数据类型 Clob 转换为 Varchar2 Oracle

c++ - 如何使用 std::vector<std::mutex> 之类的东西?