1

让我们考虑以下代码。事实上,这是我使用 gmock 和模拟 void(void) 方法发现的缩小问题。

class Base {
 public:
  virtual ~Base() {}
};

class Derived : public Base
{
 public:
  void GetValueAndDelete()  { delete this; } //here we crash
};

int main() {
  Derived* p = 0;
  p->GetValueAndDelete();
}

构建它:

/tools/gcc6.1/bin/g++ --version
g++ (GCC) 6.1.0

优化级别不同于 -O0 并且运行结果会导致分段错误。

是 gcc 错误还是带有 c++ 代码的东西(是的,是的,我知道它使用副作用,但它可以与其他编译器一起使用,并且也没有优化)

4

3 回答 3

4

是 gcc 错误吗

不。

或带有c ++代码的东西

是的。您在不指向有效对象的指针上使用箭头运算符。这具有未定义的行为。

以这种不使用任何成员的方式取消引用空指针和调用方法是可以的。

按照标准是不行的。是UB。

什么是指针上的调用方法?

是特定于实现的。

删除这个没什么特别的。

删除this很特别。

你应该只注意不要使用任何成员之后

是的,必须确保它仅new用于创建调用该函数的所有实例。没有自动对象,没有静态对象new[],没有malloc+ 放置新。

所以是的,你可以 delete this,但要小心。

于 2016-07-13T13:15:14.710 回答
2

您的直觉似乎是:

  1. p->没关系,因为它只是一种用于填写this.
  2. delete this没关系,因为你不使用thisafter delete

但上述情况实际上可能并不好,因为取消引用空指针始终是未定义的行为。如果不启用优化,这可能不会造成任何麻烦,因为编译器正在执行“基本编译”,这在某种程度上与您“在脑海中编译”时的想象相匹配。然而,通过优化,GCC 会做很多它通常不会做的事情,例如在面对不正确的源代码时不会费心发出“正确”的指令。当您说程序的第一个动作时,它实际上根本不需要做任何事情p->-它可以假装main()是空的(或崩溃,就像您的情况一样)。

于 2016-07-13T13:20:13.950 回答
0

我知道 nullptr 上的调用方法不符合标准,但到目前为止,我还没有看到无法以所述方式处理的编译器。似乎 gcc6.1 的工作方式不同(仍然根据规范)。所以这是 gmock 错误。我想知道有多少其他项目依赖于这种编译器行为:)

值得一提的是,方法被调用,里面的'this'按预期为零,然后删除失败。我查看了程序集,其中有 mov (%rax), %rbx 失败,因为 rax 包含零。

于 2016-07-13T19:15:32.497 回答