访问已经销毁的对象不会导致段错误

Accessing an already destroyed object does not cause segfault

出于乐趣,我决定看看 gdb 会怎么说这段代码,这意味着尝试使用已销毁对象的方法。

#include <iostream>

class ToDestroy
{
public:
  ToDestroy() { }
  ~ToDestroy() {
    std::cout << "Destroyed!" << std::endl;
  }
  void print() {
    std::cout << "Hello!" << std::endl;
  }
};

class Good
{
public:
  Good() { }
  ~Good() { }
  void setD(ToDestroy* p) {
    mD = p;
  }
  void useD() {
    mD->print();
  }
private:
  ToDestroy* mD;
};

int main() {
  Good g;
  {
    ToDestroy d;
    g.setD(&d);
  }
  g.useD();
  return 0;
}

输出是(使用 -O0 标志构建):

Destroyed!

Hello!

在堆中分配 d 并删除它会导致相同的行为(即不会崩溃)。

我假设内存没有被覆盖,C++ 'tricked' 可以正常使用它。但是,令我惊讶的是,在堆上分配和删除时,可以使用未分配给它们的内存。

有人可以对此提供更多见解吗?这是否意味着当尝试取消引用指针时,如果该内存恰好有一些东西 'coherent' 对于我们的上下文,尽管内存没有分配给我们,执行也不会导致 SEGFAULT?

当您尝试访问 OS 禁止您访问的地址时,会发生段错误。这可能是因为地址后面的内存未分配给您的进程,或者因为它不存在或其他原因。所以你现在正试图访问一块仍然分配给你的进程的内存,所以没有段错误。

Malloc(管理堆的那个)与某些缓冲区一起工作以限制系统调用的数量。所以有未初始化的内存你可以访问。

您向 print 传递了一个无效的 this 指针,但它从未被取消引用,因为 print 不是虚拟的,也没有访问任何成员。