C++ delete命令的原理是什么?

作者&投稿:门柳 (若有异议请与网页底部的电邮联系)
C++ delete 的机制是什么?~

delete之后 aap所指向的内存空间被释放,内存里面可能被赋予空值 可能被系统赋予随机值 ,也有可能被其它资源征用而赋予了它新的有效值 但app仍然指向那个地址 它取出来的值只能是别人的 就像你把房子卖了 你身份证上面的地址仍然是你房子的地址 但里面的内容已经不属于你了
另外在Linux下面运行结果也会不 一样 因为它的内存管理没Windows规范和严谨


如果只用delete释放内存 而不用aap=NULL;就产生了野指针

在你创建动态数组的时候系统会记录会创建的数组大小(通常是动态数组前面的空间),从而在你使用匹配的delete[]时候会正好释放那么多空间。

我们编译出来的程序运行时是和操作系统打交道的,程序中用到的内存都向操作系统申请,在多任务的操作系统下,不允许普通的程序访问未分配的内存。

操作系统手里有一张表,标明内存中的哪些单元被哪个程序占用了,哪些是空闲的(空闲不一定是空值,我们编写的程序如果动态变量没有初始化往往会带有不定值,就是这个缘故),当程序提出申请,它就把空闲的内存分配给程序。程序运行完后操作系统再把分配给的内存标记为空闲,以供其他程序用。

其实我们完全留意到,向磁盘写东西的时候很慢,但把写进了的东西删掉的时候却快得多,原因就在于操作系统删除文件的时候偷懒了,并没有彻底粉碎文件的每一个数据,而是在那张文件分配表上将这个文件所在的区域标记为空闲罢了,多数数据仍然在那里,从而给数据恢复软件留下了后门。

楼主的程序前面会申请空间来存放类A和B的对象。执行到delete就会去内存的堆区将指定的内存单元交还给操作系统。所以必须和new配套使用,否则会酿成严重后果。
我个人的猜测,执行delete只是将它后面变量的地址告诉给操作系统,操作系统把它手里的那张表给改了,但delete掉的指针没有变化,还是原来指向的变量的地址值。可以运行一下这个小程序:
#include <iostream.h>
int main(void)
{
int *p;
p=new int;
cout<<(unsigned int)p<<endl;//1
delete p;
cout<<(unsigned int)p<<endl;//2
p=NULL;
cout<<p;
return 0;
}
可以看到,delete前后,指针p的值没有变化。但是如果将2处改为cout<<*p;就要出问题了,操作系统会阻止程序去访问这个地址(表现为访问冲突,Access Violation),因为这个地址已经用delete归还给操作系统了。这时候的指针p叫做悬空状态,也就是野指针,怎么称呼都无所谓。它并没有被销毁,通过重新取其他变量的地址,还可以继续访问*p,但现在不行。

指针实际上是一个无符号整型变量,几乎所有我们碰到的指针,在C++下都是4个字节,因为C++在32位机上将int实现得和long int一样大小。
那么为什么要给指针规定类型呢?我猜测,这一方面是为了访问它指向的对象时确定读取内存单元的长度,比如char型变量占1个字节,int型变量占4个字节,类对象和结构体对象占的长度更加多样化,当定义了一个char型指针p,执行*p时程序只读取一个字节的内容,如果p是int型则*p读取4个连续的字节的内容。还有指针相加减,指针自增自减运算,都可以通过这个来确定一次移动的长度。
另一方面,也防止乱指发生意外吧,C语言中printf和scanf的格式控制串就要用的时候亲自设定,如果设不对运行时就可能出错。

  C++ delete命令的原理如下:
  delete也分为两种情况:
  1,简单数据类型(包括基本数据类型和不需要析构函数的类型)。

  [cpp] view plaincopy
  int *p = new int(1);
  delete p;
  delete的汇编码如下:
  [cpp] view plaincopy
  delete p;
  00275314 mov eax,dword ptr [p]
  00275317 mov dword ptr [ebp-0D4h],eax
  0027531D mov ecx,dword ptr [ebp-0D4h]
  00275323 push ecx
  00275324 call operator delete (0271127h)
  分析:传入参数p之后调用operator delete,其源码如下:
  [cpp] view plaincopy
  void operator delete( void * p )
  {
  RTCCALLBACK(_RTC_Free_hook, (p, 0));
  
  free( p );
  }
  RTCCALLBACK默认是空的宏定义,所以这个函数默认情况下就是简单的调用free函数。

  总结:
  delete简单数据类型默认只是调用free函数。
  2,复杂数据类型(需要由析构函数销毁对象)
  代码实例:
  [cpp] view plaincopy
  class Object
  {
  public:
  Object()
  {
  _val = 1;
  }
  
  ~Object()
  {
  cout << "destroy object" << endl;
  }
  private:
  int _val;
  };
  
  void main()
  {
  Object* p = new Object;
  delete p;
  }
  部分汇编码如下:
  [cpp] view plaincopy
  012241F0 mov dword ptr [this],ecx
  012241F3 mov ecx,dword ptr [this]
  012241F6 call Object::~Object (0122111Dh) //先调用析构函数
  012241FB mov eax,dword ptr [ebp+8]
  012241FE and eax,1
  01224201 je Object::`scalar deleting destructor'+3Fh (0122420Fh)
  01224203 mov eax,dword ptr [this]
  01224206 push eax
  01224207 call operator delete (01221145h)
  0122420C add esp,4
  总结:
  delete复杂数据类型先调用析构函数再调用operator delete。

关于这个问题。我前几天刚好在 Effective C++里看到。
这种问题牵扯到 虚析构函数。

大概是这样的:
比如
A*p=new B;
。。。
delete p;
如果父类的 析构函数不是一个虚函数 。那么delete p这样的行为是不可预测的——无法知道将会发生什么。
C++语言标准关于这个问题的阐述非常清楚:当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的(实际运行时经常发生的是,派生类的析构函数永远不会被调用。)

为了避免这个问题,只需要使A的析构函数为virtual。声明析构函数为虚就会带来你所希望的运行良好的行为:对象内存释放时,A和B的析构函数都会被调用。

关于第二个问题 delete p只是释放指针指向的内存所存储的数据,并不会改变指针所保存的地址。因此执行完这个操作可以
设置p=NULL
我执行了delete p,cout<<p<<endl是可以输出p所保存的内存地址的。

delete之后 aap所指向的内存空间被释放,内存里面可能被赋予空值 可能被系统赋予随机值 ,也有可能被其它资源征用而赋予了它新的有效值 但app仍然指向那个地址 它取出来的值只能是别人的 就像你把房子卖了 你身份证上面的地址仍然是你房子的地址 但里面的内容已经不属于你了
另外在Linux下面运行结果也会不 一样 因为它的内存管理没Windows规范和严谨

如果只用delete释放内存 而不用aap=NULL;就产生了野指针

delete p;
cout << "释放后"<<endl;
cout <<"p的指向"<< p <<endl;
cout <<"p所指向空间的大小"<<*p <<endl;
* p = 9;
p被delete 后,p的值不会改变,还是原来的值,但不能再使用p指向的内存了,你的程序刚好在这里没有出错,但这时p指向的这块内存已经不属于你的程序的内存,如果其它的程序申请内存时也申请到了这块内存,你再对p的内存进行操作是危险的,因为你在改变其他程序的内存值。


高邮市13029916839: C++中的delete的机制是怎样的呢 -
索项牛黄: delete 是C++中释放内存的运算符 1)C++程序员需要自己维护堆的内存; 2)堆的空间远大于栈,栈是系统自己维护的; 3)堆中申请内存是用new; 4)delete是专门用来释放用new申请的对象或者内存的.

高邮市13029916839: C++ delete 的机制是什么? -
索项牛黄: delete之后 aap所指向的内存空间被释放,内存里面可能被赋予空值 可能被系统赋予随机值 ,也有可能被其它资源征用而赋予了它新的有效值 但app仍然指向那个地址 它取出来的值只能是别人的 就像你把房子卖了 你身份证上面的地址仍然是你房子的地址 但里面的内容已经不属于你了 另外在Linux下面运行结果也会不 一样 因为它的内存管理没Windows规范和严谨 如果只用delete释放内存 而不用aap=NULL;就产生了野指针

高邮市13029916839: C++ delete命令的原理是什么?
索项牛黄: 我们编译出来的程序运行时是和操作系统打交道的,程序中用到的内存都向操作系统申请,在多任务的操作系统下,不允许普通的程序访问未分配的内存. 操作系统手里有一张表,标明内存中的哪些单元被哪个程序占用了,哪些是空闲的(空闲...

高邮市13029916839: c++中的delete的操作到底是怎么回事?? -
索项牛黄: 00399208 代表的是p这个指针指向的地址值,在delete之前输出的那个5代表p这个指针指向的一个int空间里面存放的数值; 在你delete之后,p这个指针没有变化,仍然是00399208,但是它指向的空间已经被释放了,所以输出的就是一个“不确定”的数值:-57266307.对于问题的补充: 2.如果在程序代码后面再加上*p=5;cout<<*p<<endl; 可以再输出一个5;注意已经使用了delete操作. 空间虽然释放了,但那时p这个指针仍然是有效的,它指向的内存仍然是可写的,所以程序会进行正确的输出.

高邮市13029916839: C++中的delete到底是清空什么?是指针本身还是指针所指向的值? -
索项牛黄: C++的delete要执行两个步骤:1 按照指针类型,调用该类的析构函数.(这个是c的free没有的功能).2 根据指针类型,释放相应宽度的内存空间.(类似C的free).从这个题目来说,delete是是否指针所指向的对象.而不是释放指针本身.一般而言,delete p;以后最后跟一个 p=NULL;避免无效指针的二次访问.

高邮市13029916839: C++中 delete的实质是什么? -
索项牛黄: delete之后,下次再重新申请的时候可以再申请这块内存地址,也就是将这块地址放到了空闲链表上,对于这块地址的内容,没有进行清空处理(也没有必要);由于你没有将p赋为NULL,所以p指针还是指向这块内存空间.如果不delete的话,你这块内存是不能在申请使用的,也就是所谓的内存泄露.对于delete之后的指针p,此时是“野指针”.一般的正确做法是:int * p = new int ; if (p == NULL)(千万不要忘了这句话!!!) { //判断是否为空!使用空指针是不对的!!} delete p; p = NULL;(千万不要忘了这一句话!!) 上面所说的,希望能理解……

高邮市13029916839: C++delete 动态清除内存占用的机制 -
索项牛黄: 删除内存只是把内存还给堆,从而可以下次再分配,这个内存里面的值本身是不会去改变的.就好像你离开酒店,退房,在整理房间之前,房间里面的东西和你走的时候还是一样的放置的.如果房间整理了,或者又给新的客人住了,那里才会发生变化.你用指针访问 delete之后的内存,在实际软件开发中是一个危险操作

高邮市13029916839: c++中的delete到底怎么回事啊? -
索项牛黄: 对于简单类,delete p 与delete[] 是等价的,编译器有这方面的优化处理 但是对于比较复杂的类类型,这两者就不等价了,这时候如果用delete而不是delete[]的话 就会有内存泄漏了.

高邮市13029916839: c++中是如何实现数据的保存和删除的? -
索项牛黄: 栈:是由编译器在需要时自动分配,不需要时自动清除的变量存储区.通常存放局部变量、函数参数等. 堆:是由new分配的内存块,由程序员释放(编译器不管),一般一个new与一个delete对应,一个new[]与一个delete[]对应.如果程序员没有释放 掉,资源将由操作系统在程序结束后自动回收. 自由存储区:是由malloc等分配的内存块,和堆十分相似,用free来释放. 全局/静态存储区:全局变量和静态变量被分配到同一块内存中(在C语言中,全局变量又分为初始化的和未初始化的,C++中没有这一区分). 常量存储区:这是一块特殊存储区,里边存放常量,不允许修改.

高邮市13029916839: c++ delete的作用:是删除对象还是删除指针? -
索项牛黄: delete是删除指针指向的对象,让其释放内存.指针中的地址不变,所以一般在delete指针后,要将该指针的值赋值NULL(置空).

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网