在NULL指针上访问类成员 [英] Accessing class members on a NULL pointer

查看:142
本文介绍了在NULL指针上访问类成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在试验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.

我有以下问题


  1. 非虚法 say_hi 处理NULL指针?

  2. 对象 foo

  1. How does the non virtual method say_hi work on a NULL pointer?
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆