当前位置:   article > 正文

Cpp指针的delete操作 - 小记_cpp delete

cpp delete

Cpp指针的delete操作 - 小记

  在学习C++/数据结构的链表部分时,我留意到了一处有关于关键字delete的操作细节。new和delete是C++中经常成对使用的关键字,用于开辟/删除内存空间、并将地址赋值于等号左边指针变量;关于delete,边学习边刷链表题时留意到使用delete清除临时指针变量、释放内存的操作,结合要防止指针ptr成为野指针的目的,通常还需要加一条如 p t r = n u l l p t r ptr=nullptr ptr=nullptr来达成。
而在一开始学习接触时,混淆应该是先delete指针内存、还是先清空指针内容,即搞不清楚两条语句的顺序,因此写了小小的一个测试例子,Debug看一下对比效果。

1.先赋值为空,再delete

初始化定义好指针指向链表头节点后,赋值临时指针ptr,然后将其赋值为指向空指针,再delete释放内存。

    int arr1[3]={1,2,3};
    Node *head=gen_listnode(arr1,3);
    Node *ptr=head;
    ptr=nullptr;
    delete ptr;
  • 1
  • 2
  • 3
  • 4
  • 5

设置断点启动Debug,可以看到再经历先赋值为空再delete掉指针的话,只是指针变量ptr自己被清空,自身占用内存被释放;而该指针ptr指向的节点变量head没有被清除(即ptr指向内存没被清空):对指针先赋值为空->再delete清除
当然,肯定有小伙伴问,直接赋值为null不就完事了,为啥还要delete?这是因为如果不delete的话,cpu中该指针变量实际上仍然存在,只不过现在为空指针没指向任何变量而已——但本身仍然在占用该地址/消耗内存呢,因此还需要delete掉解除占用,这样原指针变量的那块“地盘”才能恢复给cpu动态赋予其他变量申请使用,总不能“占着茅坑不拉屎”对吧!

2.先delete,再赋值为空指针

  如果对该指针变量ptr先使用delete、再赋值为空的话,即有:

    /* 指针变量中,存储的是指向的变量的地址符; */
    int c1=&a;
    int c2=p;
    printf("%d\n",c1);
    printf("%d\n",c2);
    //可以看到c1和c2输出结果一样,说明指针里面存的就是指向的变量的地址~
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在delete之前:
指针ptr在指向链表节点head;

在这里插入图片描述在这里插入图片描述
在delete执行后:
由于ptr指向了head所在地址,delete了指针ptr实际上即把head占用的内存也给释放掉了,这时,原地址上的变量(链表节点)随同ptr指针,经内存被释放、指针成为了指向“未知”的野指针:

在这里插入图片描述
在这里插入图片描述
为避免这样的野指针指向“未知”的空间,防止在之后重定义使用该变量名时可能产生难以想象的错误,必须禁止野指针的出现!必须禁止野指针的出现!(这或许算是C/C++编程中需要牢记的一项法则了吧。。),因此,还需要对该指针变量赋为空指针——即不指向任何内存空间,这样后再来看,节点变量head和指向他的指针ptr此时都为空指针/(NULL)了:

在这里插入图片描述
因为head并不是节点变量的真实名,而是一个new出来的指向真实变量地址的指针(在前文描述中把他称为节点变量只是方便区分和ptr指针的描述,实际就是俩指向同一块地址的俩指针。。),所以在操作 p t r = n u l l p t r ptr=nullptr ptr=nullptr后head并没有随同ptr指针被清空,如果你看着这个head也挺碍眼的话,可以一起 h e a d = p t r = n u l l p t r head=ptr=nullptr head=ptr=nullptr的啦哈哈哈。

  当然,就我这里链表部分的学习内容来说,delete+清空为NULL这套操作一般是用于删除链表节点的,而链表节点没有单独说存在一个所谓“真实变量名”(或者说,毕竟你的链表节点是“new”出来的,有new才有的delete,new生成的一定是指针变量),节点的链接指向是通过上一链表节点存放其所在地址来供用户“索引"的,如果你加了个临时指针变量ptr指向它,并采用上文对指针ptr先delete再清空为NULL的话,这块地址上的东西确实被解除内存占用且清空了,就不用担心存在上图这样“别扭”的状况啦。~~

** 全文测验代码如下:

#include <iostream>
using namespace std;

typedef struct ListNode{
    int val;
    ListNode* next;
    ListNode():val(0),next(nullptr) {}
    ListNode(int x):val(x),next(nullptr) {}
    ListNode(int x,ListNode *p):val(x),next(p) {}
}Node;

Node* gen_listnode(int *arr,int _size)
{
    int k=_size;
    Node *ptr=new Node(arr[0]);
    Node *_head=ptr;
    for(k=1;k<_size;k++)
    {
       ptr->next=new Node(arr[k]);
       ptr=ptr->next;
    }
    return _head;
}

int main(void)
{
    int arr1[3]={1,2,3};
    Node *head=gen_listnode(arr1,3);
    Node *ptr=head;
    //这里放个断点,往下执行,感受下~
    //先清空指针,再释放指针内存
    ptr=nullptr;
    delete ptr;

    Node *head=gen_listnode(arr1,3);
    Node *ptr=head;
    //换断点到这,往下执行,感受下~
    //先释放指针及指向内存,再清空指针
    delete ptr;
    head=ptr=nullptr;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/728470
推荐阅读
相关标签
  

闽ICP备14008679号