0

我正在寻找对这段代码的澄清。对 A::hello() 的调用有效(我期望一个 segv)。段错误确实发生在对成员 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
}
4

5 回答 5

5

您的程序表现出未定义的行为。“似乎有效”是未定义行为的一种可能表现形式。

特别是,bla->hello()call 似乎可以工作,因为hello()它实际上并没有this以任何方式使用,所以它只是碰巧没有注意到这this不是一个有效的指针。

于 2013-10-16T17:03:15.603 回答
3

您正在取消引用NULL指针,即尝试访问存储在 address 的对象NULL

bla = NULL;
bla->hello();
bla->x = 5;

这会导致未定义的行为,这意味着任何事情都可能发生,包括分配5给成员时的段错误,以及调用方法时的x欺骗性“按预期工作”hello效果。

于 2013-10-16T17:03:02.123 回答
2

理论上,这是未定义的行为。实际上,您this在调用时不使用指针hello(),它根本不引用您的类,因此可以正常工作并且不会产生内存访问冲突。但是,当您这样做bla->x时,您试图通过bla未初始化的指针引用内存,并且它崩溃了。同样,即使在这种情况下也不能保证它会崩溃,这是未定义的行为。

于 2013-10-16T17:04:41.043 回答
1

只要成员函数不取消引用this,调用它通常是“安全的”,但您随后处于未定义的行为领域。

于 2013-10-16T17:03:11.620 回答
1

至少在典型实现中,当您通过指针调用非虚拟成员函数时,不会取消引用该指针以找到该函数。

指针的类型用于确定搜索函数名称的范围(上下文),但这完全发生在编译时。指针指向的内容(在空指针的情况下包括“无”)与查找函数本身无关。

在编译器找到正确的函数后,它通常会将类似的调用翻译a->b(c);成大致相当于:b(a, c);--a然后变成this函数内部的值。当函数引用对象中的数据时,this取消引用以找到正确的对象,然后通常应用偏移量以在该对象中找到正确的项目。

如果成员函数从不尝试使用对象的任何成员,this则空指针这一事实不会影响任何事情。

另一方面,如果成员函数确实尝试使用对象的成员,它将尝试取消引用this以执行此操作,并且如果this是 NULL 指针,那将不起作用。同样,调用虚函数总是使用对象中的 vtable 指针,因此尝试通过空指针调用虚函数可能会失败(无论虚函数中的代码是否引用对象中的数据或不)。

正如我所说的那样,我在这里谈论的是典型的实现。从标准的角度来看,您只是有未定义的行为,这就是它的结束。理论上,实现不必像描述的那样工作。然而,实际上,基本上所有相当流行的 C++ 实现(例如,MS VC++、g++、Clang 和 Intel)在这些方面都非常相似。

于 2013-10-16T17:20:17.870 回答