在NULL指针上访问类成员 [英] Accessing class members on a NULL pointer
问题描述
我在试验C ++,发现下面的代码很奇怪。
I was experimenting with C++ and found the below code as very strange.
class Foo{
public:
virtual void say_virtual_hi(){
std::cout << "Virtual Hi";
}
void say_hi()
{
std::cout << "Hi";
}
};
int main(int argc, char** argv)
{
Foo* foo = 0;
foo->say_hi(); // works well
foo->say_virtual_hi(); // will crash the app
return 0;
}
我知道虚拟方法调用崩溃,因为它需要一个vtable查找,只适用于有效对象。
I know that the virtual method call crashes because it requires a vtable lookup and can only work with valid objects.
我有以下问题
- 非虚法
say_hi
处理NULL指针? - 对象
foo
- How does the non virtual method
say_hi
work on a NULL pointer? - Where does the object
foo
get allocated?
任何想法?
推荐答案
对象 foo
是类型为 Foo *
的局部变量。这个变量可能在 main
函数的栈上被分配,就像任何其他局部变量一样。但是存储在 foo
中的值是一个空指针。它不指向任何地方。
The object foo
is a local variable with type Foo*
. That variable likely gets allocated on the stack for the main
function, just like any other local variable. But the value stored in foo
is a null pointer. It doesn't point anywhere. There is no instance of type Foo
represented anywhere.
要调用虚函数,调用者需要知道哪个对象的功能被调用。这是因为对象本身是什么告诉哪个函数应该被调用。 (这通常通过给对象一个指向vtable的指针,一个函数指针列表,调用者只知道它应该调用列表上的第一个函数,而不知道该指针指向的位置)来实现。)
To call a virtual function, the caller needs to know which object the function is being called on. That's because the object itself is what tells which function should really be called. (That's frequently implemented by giving the object a pointer to a vtable, a list of function-pointers, and the caller just knows it's supposed to call the first function on the list, without knowing in advance where that pointer points.)
但是为了调用非虚函数,调用者不需要知道所有的。编译器确切知道哪个函数将被调用,因此它可以生成 CALL
机器码指令直接转到所需的函数。它只是传递一个指向函数被调用的对象的指针作为函数的隐藏参数。换句话说,编译器将你的函数调用转换为:
But to call a non-virtual function, the caller doesn't need to know all that. The compiler knows exactly which function will get called, so it can generate a CALL
machine-code instruction to go directly to the desired function. It simply passes a pointer to the object the function was called on as a hidden parameter to the function. In other words, the compiler translates your function call into this:
void Foo_say_hi(Foo* this);
Foo_say_hi(foo);
现在,由于该函数的实现从不引用其指向的对象的任何成员这个
参数,你有效地躲避反引用一个空指针的项目符号,因为你从不取消引用一个。
Now, since the implementation of that function never makes reference to any members of the object pointed to by its this
argument, you effectively dodge the bullet of dereferencing a null pointer because you never dereference one.
对空指针的任何函数(即使是非虚拟函数)是未定义的行为。未定义行为的允许结果之一是,您的代码似乎运行完全如你所愿。 不应该依赖于这一点,但有时会发现您的编译器供应商提供的库依赖于这些。但是编译器供应商具有能够将另外的定义添加到否则将是未定义的行为的优点。不要自己动手。
Formally, calling any function — even a non-virtual one — on a null pointer is undefined behavior. One of the allowed results of undefined behavior is that your code appears to run exactly as you intended. You shouldn't rely on that, although you will sometimes find libraries from your compiler vendor that do rely on that. But the compiler vendor has the advantage of being able to add further definition to what would otherwise be undefined behavior. Don't do it yourself.
这篇关于在NULL指针上访问类成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!