为什么悬空指针可以继续访问对象

why the dangling pointer can go on access the object?

本文关键字:继续 访问 对象 空指针 为什么      更新时间:2023-10-16

我对野生指针和悬挂指针的一些细节感到困惑,这是我的代码:

#include <iostream>
using std::cout;
using std::endl;
class A
{
public:
    void Func() { cout << "Func of class A, the address is:" << this <<endl; }
};
void Test(void)
{
    A *p;
    //get an error in VS2013 because of uninitialized pointer.
    //But it's ok in g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2
    p->Func();     // wild pointer, ((1))
    {
        A a;
        p = &a; 
        p->Func();
    }
    p->Func();  //dangling pointer  ((2))
}
int main()
{
    Test(); 
    return 0;
}

结果如下:
窗口:
Func of class A, the address is:003CFD47 Func of class A, the address is:003CFD47

Ubuntu:
Func of class A, the address is:0xb74ef39d Func of class A, the address is:0xbff85a3b Func of class A, the address is:0xbff85a3b

我的问题:
(1) g++编译器让wile指针在((1))处传递,即使在运行代码时,它似乎也指向"某个对象"。为什么会发生这种情况?是编译器的错误吗?

(2) 据我所知,在块语句之后,p将是((2))处的一个悬空指针。但是为什么p可以继续指向Func()呢?因为对象a占用的空间没有被其他应用程序覆盖?

p最初未初始化,因此它包含了为p保留的调用堆栈区域中的任何随机值。这就是您在第一个cout输出中看到的内容。

然后创建一个对象并将其地址分配给p,这在第二个cout输出中可以看到。

然后,对象超出范围并被释放,但您没有将任何内容重新分配给p,因此它携带其现有值,您可以在第三个cout输出中看到。

当通过无效指针调用对象方法时,尽管在技术上没有定义行为,但只要不取消引用指针以访问类的任何成员,包括任何需要VMT指针的虚拟方法,通常不会发生任何错误。

方法调用实际上只是一个带有额外隐藏的this参数的函数调用,因此您的示例代码实际上是从编译器的角度执行以下操作:

#include <iostream>
using std::cout;
using std::endl;
class A
{
public:
    static void Func(A* this) { cout.operator<<("Func of class A, the address is:").operator<<((void*)this).operator<<(&endl); }
};
void Test(void)
{
    A *p; // initialized with random value 
    A::Func(p);
    {
        A a; // note: allocates only
        A::A(&a); // then constructs
        p = &a; 
        A::Func(p);
        A::~A(&a);
    }
    A::Func(p);
}
int main()
{
    Test(); 
    return 0;
}