我对野指针和悬空指针的一些细节感到困惑,这是我的代码:
#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))处传递,即使在运行代码时,它似乎指向“某个对象”。为什么会发生这种情况?是编译器的bug吗?
(2) 据我所知,在 block 语句之后,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;
}
关于c++ - 为什么悬空指针可以继续访问对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26625304/