【问题标题】:How Foo *p = 0;p->p() is valid? [duplicate]Foo *p = 0;p->p() 如何有效? [复制]
【发布时间】:2017-08-06 01:29:24
【问题描述】:
class Foo
{
public:
    Foo(int i)
    {
        _i = i;
    }
    void p()
    {
        cout<<"printed"<<endl;
    }
    int _i;
};
int main()
{
    Foo *p = 0;
    cout <<p<<endl;
    p->p();

    return 0;
}

以上代码的实际输出为

0
printed

据我了解,访问 0x0 地址应该会导致 SEG 错误。 因为*p地址是0x0。

它为什么起作用?有人解释一下吗?

【问题讨论】:

  • 这是Undefined Behaviour。任何事情都可能发生,直到并包括出现工作。在这种情况下,如果您真的想看到崩溃,请尝试在 Foo 中添加一个成员变量,在 Foo::p() 中打印,以实际强制计算机尝试访问无效地址的一些内存。
  • 取消引用空指针始终是未定义的行为。 然而,你“只是”调用一个成员函数,因此编译器实际上并没有取消引用指针,它只是跳转到一些代码。如果在函数内部使用this(例如打印_i 的值),情况就完全不同了。
  • 因为事实上*p 没有在任何地方被取消引用。一个类的方法有一个包含this的隐藏参数,所以你的调用被翻译成methodp(pointerp);没有取消引用。请注意,如果 methodpvirtual,那么您肯定会崩溃
  • 当您调用未定义行为时,您的程序不受 C++ 语言的任何语义保证。
  • 如果你真的想增加你的故障几率,添加&lt;&lt; _i到你在p()的输出。无论如何,您正在调用未定义的行为。想想你自己不幸它没有在你预期的时候崩溃。

标签: c++


【解决方案1】:

因为 p() 是一个普通方法(即不是虚拟的),所以对 p->p() 的调用可以在编译时解决,而且由于你不要访问 p 的任何成员,方法内不需要有效的 this 指针。

编辑:.. 但如上所述,这实际上是未定义的行为。

【讨论】:

  • 这个答案是不完整的(而且很危险),没有提到虽然这就是它在实践中似乎有效的原因,但它仍然是未定义的行为。
【解决方案2】:

这是无效的。但是 undefined beheviour 不保证段错误或任何东西。

你不能在这里依赖任何东西,所以不要这样做。它可以(似乎)工作,它可以崩溃,它可以烧毁你的电脑,任何东西。

在这种特殊情况下,方法 p() 不依赖于其类中的任何其他内容,并且允许编译器假设您的代码中没有 UB,因此它很可能只是执行 p 甚至不做任何事情使用指针(但同样不能保证编译器会这样工作)。

【讨论】:

  • 无法烧录你的电脑
  • @user 当然可以。它甚至可以杀人(而且已经这样做了)。
  • 我不会说“它可以工作”,因为没有定义正确的行为。从逻辑上讲,它是行不通的。
  • 它也不能让外星人入侵地球
  • @Aziuth 不,它正在工作,因为 *p 没有被取消引用。编译器没有“理解”任何东西。编译器可以选择取消引用 *p 的原因可能有 1,000,000 个(例如,用于安全检查、日志记录或???),但通常编译器不会这样做,除非程序或函数要求它是虚拟的。
猜你喜欢
  • 2019-11-06
  • 2018-03-16
  • 2014-12-18
  • 1970-01-01
  • 2015-08-20
  • 2018-04-29
  • 2014-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多