Joh*_* H. 3 gdb destructor type-conversion stdstring c++11
根据/sf/answers/791825051/中的@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
Run Code Online (Sandbox Code Playgroud)
效果很好:
(gdb) newstr $foo "hello world"
(gdb) p $foo->c_str()
$57 = 0xb22e388 "hello world"
Run Code Online (Sandbox Code Playgroud)
我newstr在其他自定义 gdb 命令中使用,因此为了整洁我还创建了delstr:
define delstr
call ($arg0)->~basic_string($arg0)
call free($arg0)
set ($arg0)=(void*)0
end
Run Code Online (Sandbox Code Playgroud)
它可以工作,但是析构函数调用会产生一条恼人的消息:
(gdb) delstr $foo
warning: Using non-standard conversion to match method std::string::~basic_string to supplied arguments
$62 = 0
Run Code Online (Sandbox Code Playgroud)
我可以避免出现“非标准转换”消息吗?(我使用的是 gdb 7.10。)
0给析构函数,而不是$foo.define delstr\ncall ($arg0)->~basic_string(0)\n# ^\ncall free($arg0)\nset ($arg0)=(void*)0\nend\nRun Code Online (Sandbox Code Playgroud)\n\n好吧,到底发生了什么......我们可以首先检查析构函数的签名。它确实需要一个整数:
\n\n(gdb) p ((Foo*) 0)->~Foo\n$1 = {void (Foo * const, int)} 0x555555554c00 <Foo::~Foo()>\n\n(gdb) p ((\'std::__cxx11::string\'*) 0)->~basic_string\n$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()>\n\n(gdb) ptype Foo\ntype = struct Foo {\n public:\n Foo(void);\n ~Foo(int);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n所以“非标准转换”警告是关于将指针转换为整数,这确实是非标准的。(该警告与析构函数无关。)
\n\n但是,出于什么深刻的原因,我们首先需要向析构函数传递一个额外的整数呢?事实证明,它实际上是 \xe2\x80\xa6 的一个错误 GCC 问题(从 gcc 6.3.0 开始),因为使用 clang 编译的同一程序(从 clang 3.8.1 开始)没有那个额外的int参数。
应该知道,在 Italium C++ ABI 中实际上有三个析构函数(D0、D1、D2)。
\n\nGCC 有一个优化-fdeclone-ctor-dtor,将三个析构函数的公共部分重构为“D4”析构函数。这个“D4”析构函数需要一个额外的参数__in_chrg来确定 D0/D1/D2 中哪一个是源,以了解是否调用虚拟基析构函数。
这个“D4”析构函数在某种程度上也被用作 GCC 生成的 DWARF 符号的规范析构函数声明。如果我们检查GCC 问题,使用“D4”的原因是 GCC 开发人员不想选择 D0、D1 或 D2 中的哪一个来祝福。
\n\n结果是额外的intGDB 没有忽略的额外结果。
该__in_chrg值是2当析构函数能够“完全对象析构”时(D0、D1),以及0当它只是“基础对象析构函数”时(D2)。由于 astd::string没有虚拟基类,因此您应该只传递0该参数。
注意:我用这个程序来测试 GDB:
\n\n#include <string>\n#include <iostream>\nstd::string aa;\nstruct Foo {\n Foo() { std::cout << "Constructing: this = " << this << std::endl; }\n ~Foo() { std::cout << "Destroying: this = " << this << std::endl; }\n};\nint main() {\n Foo foo;\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n