在线编程在线课堂在线测评Anycodes在线编程

编程论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

How to use bs4??
本帖最后由 carry0987 于
Double Queue 问题描述 : The new founded Balkan Investment Group Bank (
John 问题描述 : Little John is playing very funny game
linux-command Linux命令大全搜索工具,内容包含Linux命令
Coati 是一款跨平台的代码查看工具,适用于 C/C++ 和 Java。商业软件。特性:1. 索引
系统可承载海量并发,消息收发确认机制 保障消息必达 系统采用动态智
全平台视频监控,支持安卓苹果以及pcweb,支持海康大华等主流dvr,全部源码以及文档 单聊、群聊、商
如何访问类的私有属性? 下面以 TPathData 为例,
问题:从 XE4 以来,Firemonkey 曲线绘图在移动平台不平滑的问题一直令人诟病,提交到官方的 QC 也是族繁不及备载,官方似乎有意的
操作数据库(RODBC)   odbcConnect(dsn, uid="", p
数据模式:mode函数显示任何对象的模式。常见的单个的
系统可承载海量并发,消息收发确认机制 保障消息必达 系统采用动态智
RabbitMQ与PHP(一) 项
Iease团队扩编预备中,盼望能有Ruby或者java工程师加盟。全职兼职都可以。有爱好的伴侣请与我接洽。 邮件:i
ruby 怎么设置装备摆设GTK2,求教指导下!
#include #include #include #include using namespace std; int main() {
标题如图所示: 有n盏灯,编号1~n。一开端灯都是关着的
成熟的消息收发确认机制,支持万人大群 支持开发自定义的消息sdk接口,扩展性超强 支持单/
成熟的消息收发确认机制,支持万人大群 支持开发自定义的消息sdk接口,扩展性超强 支持单/
1. 注意列表和集合的区别 set 列表表现形式: list_1
Ajax   Ajax即“Asynchronous Javascript And
大师好,我比来在做布谷鸟优
分辨提取A和B图像Harris角点,接下来须要对

[C++分享] 内存的分配VS回收&构造函数VS析构函数

[复制链接]
发表于 2016-11-16 19:02:04 | 显示全部楼层 |阅读模式
之前有一个问题一直困扰着我,就是一个变量出了作用域,我以为这个变量的内存就被回收了,其实不是这样的,昨天问了一个高手,才豁然开朗,自己在看相关代码的反汇编代码,才知道原来真是这样就。这个问题,我想简单的说一下内存的分配VS回收&构造函数VS析构函数之间的关系。

我的疑问:为什么p出了作用域,指向p的ptr还能读到p中arr的内容,难道p出了作用域,还没有析构?

内存的分配VS回收&构造函数VS析构函数

内存的分配VS回收&构造函数VS析构函数

下面的内容会解答这个疑问,先说说跟这篇文章有关的内容。
可能是因为平时习惯的原因,我们在实例化一个对象的时候,往往是一条语句实现两个功能:1分配内存;2调用构造函数
  1. class A
  2. {
  3. public:
  4.     A()
  5.     {
  6.         i=0;
  7.         j=0;
  8.     }

  9.     ~A(){}
  10.     int i;
  11.     int j;
  12. };

  13. A a1;
  14. A * a2=new A();
复制代码
这两中方式都是一步实现两个操作,分配内存和调用构造函数,如果A没写构造函数,即没有构造函数(编译器也不会自动生成),当然就不需要调用构造函数。
其实这两步是可以分开的,A a1;这句分开不了这两步,但A * a2=new A();是可以分开,同等的代码如下:
void* memory=operator new(sizeof(A));//分配内存
A* a2=new(memory) A();//在memory上调用A的构造函数
回收的时候,我们可以这样写:
delete a2;//这句等同下面两句

//a2->~A();

//operator delete(memory);

如果A没有析构函数,当然delete时也不会调用,原因请看我的博客:构造函数产生的点及原因
也就是说A* a=new A();delete a;这两条语句,执行了四个操作:
分配内存->调用构造函数->调用析构函数->回收内存;
更多关于这四步分开的代码:

内存的分配VS回收&构造函数VS析构函数

内存的分配VS回收&构造函数VS析构函数

而我今天要说的是,这四步是完全可以分开的。既然这四步是可以分开的,那么解答上面那个疑问就很简单了。
Char* ptr;
{
      Point p;
      ptr=p;
}
P出了作用域,为什么ptr还能读到他的内容,原因很简单:因为上面几行代码只执行了前面三步,最后一步回收内存,还没有执行。出了作用域,就会执行析构,没说要回收内存,栈的内存要在方法返回之前才回收,也就是说一个方法如果大量的分配内存是很容易爆栈,即是你让栈中的变量出了作用域也没用,请不要搞混了。栈内存在方法返回的时候才回收,这一点就是爆栈的最重要原因,为什么不是在变量出作用域的时候,调用完析构函数,就回收内存呢?我也不知道为什么?,看方法test11的反汇编代码,的确是在方法返回的时候才回收内存?
那个疑问的源码如下:
  1. #include "stdafx.h"
  2. #include <iostream>
  3. using namespace std;
  4.    
  5. struct Point
  6. {
  7.     char arr[10];
  8.     Point()
  9.     {
  10.         for(int i=0;i<9;i++)
  11.         {
  12.             arr[i]='a';
  13.         }
  14.         arr[9]='\0';
  15.     }
  16.     ~Point(){}
  17.     operator char*()
  18.     {
  19.         return arr;
  20.     }
  21. };

  22. void test11()
  23. {
  24.     char* ptr;
  25.     {
  26.         Point p;
  27.         ptr=p;
  28.     }
  29.     cout<<ptr<<endl;
  30. }
  31.   
  32. int _tmain(int argc, _TCHAR* argv[])
  33. {   
  34.     {  
  35.          test11();
  36.     }
  37.     system("pause");
  38.     return 0;
  39. }
复制代码
test11的反汇编代码如下:
  1. void test11()
  2. {
  3. 010431F0  push        ebp  //ebp表示栈顶指针
  4. 010431F1  mov         ebp,esp  //esp表示栈当前指针
  5. 009C31F3  push        0FFFFFFFFh  
  6. 009C31F5  push        offset __ehhandler$?test11@@YAXXZ (9CA3C8h)  
  7. 009C31FA  mov         eax,dword ptr fs:[00000000h]  
  8. 009C3200  push        eax  
  9. 009C3201  sub         esp,0E4h  
  10. 009C3207  push        ebx  
  11. 009C3208  push        esi  
  12. 009C3209  push        edi  
  13. 009C320A  lea         edi,[ebp-0F0h]  
  14. B::`scalar deleting destructor':
  15. 009C3210  mov         ecx,39h  
  16. 009C3215  mov         eax,0CCCCCCCCh  
  17. 009C321A  rep stos    dword ptr es:[edi]  
  18. 009C321C  mov         eax,dword ptr [___security_cookie (9CF070h)]  
  19. 009C3221  xor         eax,ebp  
  20. 009C3223  mov         dword ptr [ebp-10h],eax  
  21. 009C3226  push        eax  
  22. 009C3227  lea         eax,[ebp-0Ch]  
  23. 009C322A  mov         dword ptr fs:[00000000h],eax  
  24.     char* ptr;
  25.     {
  26.         Point p;
  27. 009C3230  lea         ecx,[p]  
  28. 009C3233  call        Point::Point (9C1541h)  
  29. 009C3238  mov         dword ptr [ebp-4],0  
  30.         ptr=p;
  31. 009C323F  lea         ecx,[p]  
  32. 009C3242  call        A::~A (9C1546h)  
  33. 009C3247  mov         dword ptr [ebp-18h],eax  
  34.     }
  35. 009C324A  mov         dword ptr [ebp-4],0FFFFFFFFh  
  36. 009C3251  lea         ecx,[p]  
  37. 009C3254  call        A::`scalar deleting destructor' (9C154Bh)  
  38.     cout<<ptr<<endl;
  39. 009C3259  mov         esi,esp  
  40. 009C325B  mov         eax,dword ptr [__imp_std::endl (9D039Ch)]  
  41. 009C3260  push        eax  
  42. 009C3261  mov         ecx,dword ptr [ebp-18h]  
  43. 009C3264  push        ecx  
  44. 009C3265  mov         edx,dword ptr [__imp_std::cout (9D03A0h)]  
  45. 009C326B  push        edx  
  46. 009C326C  call        std::operator<<<std::char_traits<char> > (9C132Fh)  
  47. 009C3271  add         esp,8  
  48. 009C3274  mov         ecx,eax  
  49. 009C3276  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (9D0390h)]  
  50. 009C327C  cmp         esi,esp  
  51. 009C327E  call        @ILT+960(__RTC_CheckEsp) (9C13C5h)  
  52. }
  53. 009C3283  push        edx  
  54. 009C3284  mov         ecx,ebp  
  55. 009C3286  push        eax  
  56. 009C3287  lea         edx,[ (9C32C0h)]  
  57. 009C328D  call        @ILT+350(@_RTC_CheckStackVars@8) (9C1163h)  
  58. 009C3292  pop         eax  //pop开始出栈  注意;这里才开始回收内存
  59. 09C3293   pop         edx  
  60. 009C3294  mov         ecx,dword ptr [ebp-0Ch]  
  61. 009C3297  mov         dword ptr fs:[0],ecx  
  62. 009C329E  pop         ecx  
  63. 009C329F  pop         edi  
  64. 009C32A0  pop         esi  
  65. 009C32A1  pop         ebx  
  66. 009C32A2  mov         ecx,dword ptr [ebp-10h]  
  67. 009C32A5  xor         ecx,ebp  
  68. 009C32A7  call        @ILT+65(@__security_check_cookie@4) (9C1046h)  
  69. 009C32AC  add         esp,0F0h  
  70. 009C32B2  cmp         ebp,esp  
  71. 009C32B4  call        @ILT+960(__RTC_CheckEsp) (9C13C5h)  
  72. 009C32B9  mov         esp,ebp  //栈顶指针和栈当前指针指向同一个地址,即栈的长度就是一个指针的长度
  73. 009C32BB  pop         ebp  //栈顶指针弹出,现在栈空了
  74. 009C32BC  ret  
复制代码
我有这个疑问的原因就是:我以为在出作用域的时候不仅调用析构函数,还要回收内存,其实只是调用析构函数,内存在方法返回的时候才回收。



上一篇:c++ 编译期计算 (一)
下一篇:Qt使用默认浏览器打开网页
在线编程(http://www.anycodes.cn)&编程论坛(http://www.52exe.cn)感谢您的支持!
回复

使用道具 举报

发表于 2016-12-11 08:01:54 | 显示全部楼层
Anycodes挺不错啊
在线编程(http://www.anycodes.cn)&编程论坛(http://www.52exe.cn)感谢您的支持!
回复 支持 反对

使用道具 举报

发表于 2017-3-13 21:57:09 | 显示全部楼层
不知所云
在线编程(http://www.anycodes.cn)&编程论坛(http://www.52exe.cn)感谢您的支持!
回复 支持 反对

使用道具 举报

发表于 2017-4-13 09:42:25 | 显示全部楼层
学习编程就是走向死亡
在线编程(http://www.anycodes.cn)&编程论坛(http://www.52exe.cn)感谢您的支持!
回复 支持 反对

使用道具 举报

发表于 2017-5-12 13:27:50 | 显示全部楼层
无聊啊,来看看
在线编程(http://www.anycodes.cn)&编程论坛(http://www.52exe.cn)感谢您的支持!
回复 支持 反对

使用道具 举报

发表于 2017-7-8 00:26:28 | 显示全部楼层
已阅
在线编程(http://www.anycodes.cn)&编程论坛(http://www.52exe.cn)感谢您的支持!
回复 支持 反对

使用道具 举报

发表于 2017-8-9 14:42:16 | 显示全部楼层
不错不错不错,重要的事情说三遍
在线编程(http://www.anycodes.cn)&编程论坛(http://www.52exe.cn)感谢您的支持!
回复 支持 反对

使用道具 举报

发表于 2017-8-19 01:41:51 | 显示全部楼层
啦啦啦啦
在线编程(http://www.anycodes.cn)&编程论坛(http://www.52exe.cn)感谢您的支持!
回复 支持 反对

使用道具 举报

发表于 2017-9-20 10:12:49 | 显示全部楼层
一言难尽
在线编程(http://www.anycodes.cn)&编程论坛(http://www.52exe.cn)感谢您的支持!
回复 支持 反对

使用道具 举报

发表于 2017-10-11 01:49:11 | 显示全部楼层
今天有什么新闻么
在线编程(http://www.anycodes.cn)&编程论坛(http://www.52exe.cn)感谢您的支持!
回复 支持 反对

使用道具 举报

发布主题 上个主题 下个主题 快速回复 返回列表 官方QQ群
在线客服
客 服 中 心
群 机 器 人
网站二维码
收 起 客 服

QQ|Archiver|手机版|小黑屋|Anycodes ( ICP14002806Anycodes在线编程

GMT+8, 2018-11-22 01:06 , Processed in 1.508861 second(s), 99 queries .

Powered by Anycodes

© 2001-2013 吉林市群龙科技有限公司 Inc.

快速回复 返回顶部 返回列表