析构函数释放堆区内存不是已经为空了么


class MyClass
{
    friend void friend_test(MyClass& p);//友元
public:
    MyClass(int age,string name) {
        NAME = name;
        M_nume_age = new int(age);//堆区创建的空间

    }
    ~MyClass(){
        if (M_nume_age!=NULL){
            delete M_nume_age;
            M_nume_age = NULL;
        }
    }

public:
    
    string NAME;
private:
    int* M_nume_age;
};

void friend_test(MyClass& p) { //全局函数 ->静态区
    cout << p.NAME<<"年龄: " << *p.M_nume_age << endl;
}

void test01() {
    MyClass P1(10, "P1");
    friend_test(P1);
    cout << endl;

    MyClass P2(20,"P2");
    friend_test(P2);
    cout<<endl;

    P2 = P1;
    friend_test(P2);
}

int main() {

    test01();    //局部函数

    system("pause");
    return 0;
}

//1.析构函数
        if (M_nume_age!=NULL){
            delete M_nume_age;
            M_nume_age = NULL;
}

堆区P2先析构释放让P2.M_name_age=0x000...了么  这不就是空么?
为什么P1释放的时候if (M_nume_age!=NULL)还会判断不等于空
难道NULL!=0x0000...
希望哪位道友给我说道说道

参考GPT和自己的思路:首先,NULL和0是等价的,都表示空指针。在if (M_nume_age!=NULL)判断中,其实就是在判断指针M_nume_age是否为空(即是否指向了一个有效的内存空间),如果为空才会跳过delete语句。在析构函数执行前,P1和P2的M_nume_age都指向一个有效的内存空间,但是在P2被赋值给P1时,P1的M_nume_age指向的空间被释放,所以在P1析构函数执行时需要判断M_nume_age是否为空,因为在P2赋值给P1之后,可能出现M_nume_age指向已经被释放的空间的情况。

首先,哪里有赋值成0了,我怎么没看到相关代码
其次,地址是0代表内存地址是0,虽然是个野指针但是也是个合法的地址,不是NULL

经典的 浅拷贝 和 double free 问题
这里的问题在于, 没有区分到指针的值 和指针指向的内存地址
P2.M_num_age 与 P1.M_num_age 指向同一片内存,比如 0x1234
P2 析构, P2.M_num_age 的指针被置为空
但是 P1.M_num_age 的指针 还是指向 0x1234,是 0x1234 被释放了,和 P2.M_num_age 置为空了,
除非你在析构的时候再赋一次值

修改指针的值 通常我们的函数需要传 二级指针,或者指针的引用。 : )