首页 > 解决方案 > C ++:指向对象的未分配指针可以反复安全地取消引用......为什么?

问题描述

为什么这段代码实际上可靠地工作,不是不稳定的,未定义的?它取消引用未分配的、悬空的指向对象的指针。谢谢。

#include <iostream>
using namespace std;

class Base{
    public:
    void vf()
    {
        cout<<"vf\n";
    }
    void pr(){
        cout<<"vb\n";
    }
};

int main() {
    Base* b ;

    //Base * bp = new Base;   //trying to disrupt memory
    char ar[]= "ttttttttttt"; //trying to disrupt memory

    b->pr();
    char aa[]= "ttttttttttt";
    b->vf();
    return 0;
}

标签: c++dangling-pointer

解决方案


欢迎来到未定义行为的奇妙世界!根据 C++ 规范,此问题的行为是未定义的,因此您所看到的可能在您的系统上工作但在其他系统上崩溃,反之亦然。

实际上,这里发生的事情可能是编译器如何为成员函数生成代码的产物。通常,成员函数如下所示:

void doSomething() {
    cout << "Hello!" << endl;
}

可能会被编译为像这样的自由函数:

void Base_doSomething(Base* this) {
    cout << "Hello!" << endl;
}

从这个意义上说,当你写

bf->doSomething();

编译器将其视为您已编写

Base_doSomething(bf);

并且没有任何不好的事情发生,因为Base_doSomething没有引用this指针,这是所有坏事发生的地方。

现在,这是非常脆弱的。如果您尝试读取该Base类型的任何数据成员,则此代码将崩溃,因为您正在从错误的指针中读取。类似地,如果doSomething是一个virtual函数,你会遇到崩溃,因为调用一个虚函数(通常)需要从接收者对象中读取以找到vtable以确定要调用哪个函数,然后一个悬空指针将导致错误的内存访问.

所以,总结一下:

  • 此代码会导致未定义的行为,因此不能保证您看到的特定行为会发生或跨平台工作。
  • 尽管在语法上bp->doSomething()看起来像指针解引用,但它实际上可能不涉及指针解引用。
  • 成员函数通常编译为具有this作为第一个参数传递的“隐式”指针的自由函数。
  • 虚函数的工作方式与此不同,因此您希望在那里看到不同的行为。

希望这可以帮助!


推荐阅读