delete p后,只是释放了指针中存放的地址中的内存空间。但是指针变量p仍然存在(即指针p本身所占有的内存),且p中存放的地址还是原来的地址。

例如:

  对一个非空指针delete后,若没有将p赋为NULL,若再次delete的话,会出现问题。

  如下代码:

#include <iostream>
int main()
{
int* p = new int();
delete p;
delete p;
return ;
}

在ubuntu14.04中使用g++进行编译无问题,但运行时报错如下:

意思就是对同一指针变量进行了两次释放内存的操作,这是不合法的。

因为第一次释放后,指针p指向的那块区域已经变为不可访问区域了,再执行一次delete p,试图对一块不可访问的区域进行释放,这是不合法的。

将其改为:

#include <iostream>
int main()
{
int* p = new int();
delete p;
p = NULL;
delete p;
return ;
}

则编译和运行都没有问题,因为C++保证delete值为NULL的指针是安全的。

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

具体的说明如下:

还是先看代码:

 /*
*Compile Environment:linux ubuntu14.04.5 g++
*Author: mengjia
*Date:20180520
**/
#include <iostream>
using namespace std;
int main()
{
int *p = new int;
*p = ;
cout << "将3赋给p的地址后,指针p读取的值:" << *p << endl;
cout << "删除空间前,指针p中存放的地址:" << p <<endl;
delete p;
cout<<"删除空间后,指针p存放的地址:"<< p <<endl; //在vs2017中,p中存放的地址会改变,但在g++中不会,应该是vs2017中对其进行优化了,让p指向了一个不可访问的地址,避免delete之后又误操作了p
cout << "删除空间后,指针p读取的值:" << *p << endl; //在vs2017中,对×p的访问直接会报错(引发了异常: 读取访问权限冲突),但在g++中,可
以正常往下执行。
long *p1 = new long;
*p1 = ;
cout << "创建新空间后,指针p中存放的地址:" << p << endl;
cout << "指向新空间的指针p1存放的地址:" << p1 << endl;
*p = ;
cout << "将23赋给p的地址后,指针p读取的值:" << *p << endl;
cout << "将23赋给p的地址后,指针p1读取的值:" << *p1 << endl;
delete p1;
// system("pause");
return ;
}

输出结果为:

从第13和第15行中可以看到,delete指针p前后,p中存放中地址并未改变。这就说明一个非常重要的结论:

delete一个指针后,编译器只是释放了指针中存放的地址中的内存空间,但p中存放的地址还是原来的地址。

在程序的第18行,创建了一个long型的指针p1,在20和21行的输出中发现,指针p保存的地址居然和指针p1保存的地址一毛一样。说明指针p和指针p1都指向内存的同一个地方。出现这种状态是因为编译器默认将释放掉的内存空间回收然后分配给新开辟的空间。所以行,当开辟一个可以保存long型变量的空间并且由p1来指向它时,分配的空间为p指向的内存空间。

如此,将导致两个指针同时指向同一内存空间。这在C++中是非常忌讳的。

如上,在程序中定义了*p1 = 100;而后再操作p,使*p = 23;而后读取p1指向的内存中的值,变为了23。这就会使得已经delete的指针,若操作不当,会影响到程序的其它指针。这种情况就是由于野指针p造成的。

要避免这种情况的发生,解决办法就是:

在删除一个指针之后,一定要将该指针设置成空指针,即在delete p之后,要加上: p = NULL

补充说明:

请注意程序中第15行和16行的注释,这段程序在vs2017上是编译不通过的。原因就如注释所言,vs2017对其进行了优化,delete之后,让p的指向改变了,改变为指向一个不可访问的地址,使得之后如果有任何*p相关的操作,都会直接报错。其目的,我觉得就是保证在源头断绝,不让出现野指针的情况。

但这种依赖于编译器的优化,对我们理解C++并没有好处。

delete指针以后应赋值为NULL的更多相关文章

  1. delete指针以后应赋值为NULL——QT deletelater指针以后也同样要马上赋值为NULL

    delete p后,只是释放了指针指向的内存空间.p并不会自动被置为NULL,而且指针还在,同时还指向了之前的地址 delete NULL编译器不会报错(因为delete空指针是合法的) 例: 对一个 ...

  2. C++在delete指针后要赋值为NULL

    C++标准规定:delete空指针是合法的,没有副作用. 所以我们在Delete指针后赋值为NULL或0是个好习惯.对一个非空指针delete后,若没有赋NULL,若再次delete的话 有可能出现问 ...

  3. [转载]delete指针之后应该赋值NULL

    首先,C++标准规定:delete空指针是合法的,没有副作用.但是,delete p后,只是释放了指针指向的内存空间.p并不会自动被置为NULL,而且指针还在,同时还指向了之前的地址. 问题来了,对一 ...

  4. 指针delete之后赋值为null

    1.现象 经常看到有些代码在delete之后赋值为null 2.原因 C++标准规定:delete空指针是合法的,没有副作用. 所以我们在Delete指针后赋值为NULL或0是个好习惯.对一个非空指针 ...

  5. C语言_指针变量的赋值与运算,很详细

    指针变量的赋值 指针变量同普通变量一样,使用之前不仅要定义说明, 而且必须赋予具体的值.未经赋值的指针变量不能使用, 否则将造成系统混乱,甚至死机.指针变量的赋值只能赋予地址, 决不能赋予任何其它数据 ...

  6. C++ 指针悬挂和赋值操作符的重载,拷贝构造函数实现

    指针悬挂: 问题:使用new申请的内存内存空间无法访问,也无法释放. 原因:直接对指向new申请的存储空间的指针变量进行赋值修改 后果:失去了原来的地址,原来的空间无法访问也无法释放,造成内存泄漏 还 ...

  7. 【Java讨论】引用类型赋值为null对加速垃圾回收的作用(转载)

    :有一些人认为等于null可以帮助垃圾回收机制早点发现并标识对象是垃圾.其他人则认为这没有任何帮助.是否赋值为null的问题首先在方法的内部被人提起.现在,为了更好的阐述提出的问题,我们来撰写一个Wi ...

  8. delete 指针

    #include<iostream>using namespace std;class human{public: human(){cout<<"构造";} ...

  9. [No000017C]改善C#程序的建议5:引用类型赋值为null与加速垃圾回收

    在标准的Dispose模式中(见前一篇博客“C#中标准Dispose模式的实现”),提到了需要及时释放资源,却并没有进一步细说让引用等于null是否有必要. 有一些人认为等于null可以帮助垃圾回收机 ...

随机推荐

  1. mysql根据出生日期查询年龄

    如题,根据出生日期查找计算出年龄,网上找了一大堆,数据库可以用,但是集成到mybatis它不答应了,报错.具体是大于号,小于号的问题.要我解决那个错误吗?不存在的.换一种方式就好了.而且sql语句一大 ...

  2. Part-Eight 模板与群体数据的组织

    1.方法模板 #include<iostream> using namespace std; template<typename T> void outputArray(con ...

  3. [Android] Android 使用Greendao gradle 出现 Error:Unable to find method 'org.gradle.api.tasks.TaskInputs.file(Ljava/lang/Object;)

    Android 使用Greendao gradle 出现 Error:Unable to find method 'org.gradle.api.tasks.TaskInputs.file(Ljava ...

  4. sql parser

    最近在整理很多SQL代码, 需要分析出每个SQL的目标表和源表各有哪些, 网上没有找到工作具, 打算写个工具. Java调研结果:1. 商业组件包 sqlparser 有试用版组件, 限制SQL少于1 ...

  5. MySQL随记(二)

    第一范式(1NF First Normal Format): 1. 列具有原子性(atomic) 原子(atom)是物质的最小单元, 它不能被再分割为更小的元素. 2. 表具有主键(Primary K ...

  6. 【由浅入深理解java集合】(一)——集合框架 Collction、Map

    本篇文章主要对java集合的框架进行介绍,使大家对java集合的整体框架有个了解.具体介绍了Collection接口,Map接口以及Collection接口的三个子接口Set,List,Queue. ...

  7. [译]Walkthrough: Using MSBuild

    原文 MSBuild是微软VS的Build平台. 你可以在Visual Studio或Windows命令行中运行MSBuild.在这我们使用VS创建一个MSBuild项目.你可以在VS中编辑项目文件, ...

  8. 第28月第22天 iOS动态库

    1. NIMSDK 在 5.1.0 版本之后已改为动态库,集成方式有所改变,若需要集成高于此版本的 SDK,只需要做以下步骤: 将下载的 SDK 拖动到 Targets -> General - ...

  9. Idea快捷操作

    command+N 导入jar包 在方法体内部有for循环,在IntellJ中是输入fori,然后会有一个提示,选中需要的for循环即可 System.out.println();在IntellJ中是 ...

  10. js查询参数

    /*参数查询*/ function GetQueryString(name){ var reg = new RegExp("(^|&)" + name + "=( ...