在 gdb 中调用 std::~basic_string()
Calling std::~basic_string() in gdb
根据 中的@EvanED,我创建了一个 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()
= 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
= 0
我可以避免 "non-standard conversion" 消息吗? (我使用的是 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
= {void (Foo * const, int)} 0x555555554c00 <Foo::~Foo()>
(gdb) p (('std::__cxx11::string'*) 0)->~basic_string
= {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);
}
所以"non-standard conversion"警告是关于将指针转换为整数,这确实是非标准的。 (警告与析构函数无关。)
但是出于什么深刻的原因,我们首先需要将一个额外的整数传递给析构函数?结果是…… 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
which refactors the common parts of the three destructors into a "D4" destructor. This "D4" destructor takes an extra argument __in_chrg
来确定 D0/D1/D2 中的哪一个是源代码,以知道是否调用虚拟基析构函数。
这个 "D4" 析构函数不知何故也被用作 GCC 生成的 DWARF 符号的规范析构函数声明。如果我们检查 GDB 错误报告中链接的 GCC issue,使用 "D4" 的原因是因为 GCC 开发人员不想选择 D0、D1 或 D2 中的哪一个来祝福。
结果是 GDB 没有忽略的额外 int
。
当析构函数能够"complete object destruction"(D0,D1)时__in_chrg
值是2
,当它只是一个[=57=时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;
}
根据 中的@EvanED,我创建了一个 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()
= 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
= 0
我可以避免 "non-standard conversion" 消息吗? (我使用的是 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
= {void (Foo * const, int)} 0x555555554c00 <Foo::~Foo()>
(gdb) p (('std::__cxx11::string'*) 0)->~basic_string
= {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);
}
所以"non-standard conversion"警告是关于将指针转换为整数,这确实是非标准的。 (警告与析构函数无关。)
但是出于什么深刻的原因,我们首先需要将一个额外的整数传递给析构函数?结果是…… 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
which refactors the common parts of the three destructors into a "D4" destructor. This "D4" destructor takes an extra argument __in_chrg
来确定 D0/D1/D2 中的哪一个是源代码,以知道是否调用虚拟基析构函数。
这个 "D4" 析构函数不知何故也被用作 GCC 生成的 DWARF 符号的规范析构函数声明。如果我们检查 GDB 错误报告中链接的 GCC issue,使用 "D4" 的原因是因为 GCC 开发人员不想选择 D0、D1 或 D2 中的哪一个来祝福。
结果是 GDB 没有忽略的额外 int
。
当析构函数能够"complete object destruction"(D0,D1)时__in_chrg
值是2
,当它只是一个[=57=时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;
}