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. java-Array数组常用操作例子(基础必备)

    package com.net.xinfang.reflect; import java.util.ArrayList; import java.util.Arrays; import java.ut ...

  2. [NIO-3]Socket通道

    Socket通道 上文讲述了通道.文件通道,这篇文章来讲述一下Socket通道,Socket通道与文件通道有着不一样的特征,分三点说: 1.NIO的Socket通道类可以运行于非阻塞模式并且是可选择的 ...

  3. Redis之路

    前言:数据库是一切数据的源头,因此我们没有逃避的理由 (一) 什么是redis? redis是nosql(not noly sql)产品中最为出色的一种非关系型的数据库,主要包括以下几种存储结构:St ...

  4. 【解决】Can't find default configuration "arch/x86/configs/xx_defconfig"!

    Can't find default configuration "arch/x86/configs/xx_defconfig"! 这个问题常见在没有设置好架构的makefile中 ...

  5. Entity Framework Code First 学习日记(1)精

    我最近几天正在学习Entity Framework Code First.我打算分享一系列的学习笔记,今天是第一部分: 为什么要使用Code First: 近 年来,随着domain driven d ...

  6. 让Windows Server 2008r2 IIS7.5 ASP.NET 支持10万并发请求

    由于之前使用的是默认配置,服务器最多只能处理5000个同时请求,今天下午由于某种情况造成同时请求超过5000,从而出现了上面的错误. 为了避免这样的错误,我们根据相关文档调整了设置,让服务器从设置上支 ...

  7. final 关键字:用来修饰类,方法,成员变量,局部变量

    final 关键字:用来修饰类,方法,成员变量,局部变量 表示最终的不可变的 1.final修饰一个类 表示当前的类不能有子类,也就是不能将一个类作为父类 格式: public final class ...

  8. j2ee应用开发调试工具

    j2ee应用程序不能独立运行,需要运行在一个servlet/jsp容器中,常用的servlet/jsp容器如:tomcat,jetty等.在开发调试j2ee程序时,也需要部署在一个指定的容器中.如果每 ...

  9. C# 获取当前路径方法整理

    https://www.cnblogs.com/tianma3798/p/6553863.html1. //获取包含清单的已加载文件的路径或 UNC 位置. public static string ...

  10. C# UserControl集合属性使用

    在UserControl中,定义集合属性时,如果直接使用List是检测不到在属性框中的列表修改变化的,可以通过 ObservableCollection() 实现 1.定义类 [Serializabl ...