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 中实际上有三个析构函数 (D0、D1、D2).
海湾合作委员会有一个优化-fdeclone-ctor-dtor它将三个析构函数的公共部分重构为“D4”析构函数。这个“D4”析构函数需要一个额外的参数__in_chrg判断D0/D1/D2中哪一个是源,知道是否调用虚基析构函数。
这个“D4”析构函数在某种程度上也被用作 GCC 生成的 DWARF 符号的规范析构函数声明。如果我们检查海湾合作委员会问题从 GDB 错误报告链接来看,使用“D4”的原因是 GCC 开发人员不想选择 D0、D1 或 D2 中的哪一个来祝福。
结果是额外的int
GDB 并没有忽视这一点。
The __in_chrg
值为2
当析构函数能够“完全销毁对象”时(D0,D1),并且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;
}