2014-10-29 75 views
2

我感到困惑野指针和野指针的一些细节,这里是我的代码:为什么悬挂指针可以继续访问对象?

#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; 
} 

结果就像如下:
的Windows:
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 ++编译器让wil在((1))处传递e指针,即使运行代码,它似乎指向'某个对象'。为什么会这样呢?它是编译器的错误吗? (2)据我所知,在块句之后,p将是((2))处的悬挂指针。但为什么可以继续指向Func()?由于对象a占用的空间不会被其他应用程序覆盖吗?

+3

这是不确定的行为。 – 2014-10-29 08:02:44

+0

这是?悬挂指针?@πάνταῥεῖ – kkwang 2014-10-29 08:03:34

+1

@wjk访问/取消引用它。 – 2014-10-29 08:04:13

回答

4

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; 
}