我正在寻找有关这段代码的澄清。对A :: hello()的调用有效(我期望一个segv)。 segfault确实通过对成员x的访问,所以看起来单独的方法解决方案实际上并没有解除引用bla?
我编译了优化关闭,gcc 4.6.3。为什么bla-> hello()不会爆炸?只是想知道'发生了什么事。感谢。
class A
{
public:
int x;
A() { cout << "constructing a" << endl; }
void hello()
{
cout << "hello a" << endl;
}
};
int main()
{
A * bla;
bla = NULL;
bla->hello(); // prints "hello a"
bla->x = 5; // segfault
}
答案 0 :(得分:5)
您的程序显示未定义的行为。 “似乎工作”是未定义行为的一种可能表现。
特别是,bla->hello()
调用似乎有效,因为hello()
实际上并没有以任何方式使用this
,所以它恰好没有注意到this
不是一个有效的指针。
答案 1 :(得分:3)
您正在取消引用NULL
指针,即尝试访问存储在地址NULL
的对象:
bla = NULL;
bla->hello();
bla->x = 5;
导致 未定义的行为 ,这意味着在向成员5
分配x
时会发生任何事情,包括seg错误在调用hello
方法时,还包括欺骗性“按预期工作”效果。
答案 2 :(得分:2)
理论上讲,这是未定义的行为。实际上,在调用this
时不使用hello()
指针,它根本不引用您的类,因此可以工作并且不会产生内存访问冲突。但是,当您执行bla->x
时,您试图通过未初始化的bla
指针引用内存,并且它会崩溃。同样,即使在这种情况下,也不能保证它会崩溃,这是未定义的行为。
答案 3 :(得分:1)
只要成员函数没有取消引用this
,调用它通常是“安全的”,但是你处于未定义的行为。
答案 4 :(得分:1)
至少在典型的实现中,当您通过指针调用非虚拟成员函数时,该指针不会被解引用以找到该函数。
指针的类型用于确定搜索函数名称的范围(上下文),但这完全在编译时发生。指针指向的内容(包括“无”,在空指针的情况下)与查找函数本身无关。
在编译器找到正确的函数后,它通常会将a->b(c);
之类的调用转换为大致相当于:b(a, c);
- a
的调用,然后变为this
的值在功能里面。当函数引用对象中的数据时,this
被取消引用以找到正确的对象,然后通常应用偏移量来查找该对象中的正确项。
如果成员函数从不尝试使用任何对象的成员,this
是空指针的事实不会影响任何事情。
另一方面,如果成员函数确实尝试使用该对象的成员,它将尝试取消引用this
来执行该操作,并且如果this
是NULL指针,这是行不通的。同样,调用虚函数总是使用对象中的vtable指针,因此尝试通过空指针调用虚函数可能会失败(无论虚函数中的代码是否引用对象中的数据)或不)。
正如我先说的那样,我在谈论这里的典型实现。从标准的角度来看,您只是具有未定义的行为,这就是它的结束。从理论上讲,实现不会 按照我所描述的方式工作。然而,实际上,基本上所有相当流行的C ++实现(例如,MS VC ++,g ++,Clang和Intel)在这些方面都非常相似。