CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C++ 语言

内存自动增长分配问题

楼主wiali(维埃里)2005-07-01 16:50:41 在 C/C++ / C++ 语言 提问

template<typename   T>  
  static   void   grow()    
                  {  
                      assert(sizeof(T)   >=   sizeof(void*));  
  int   items   =   ((128*1024   +   sizeof(T)   -   1)/sizeof(T));  
  static   void*   freeList   =   new   char[sizeof(T)*items];  
  char*   tmp   =   (char*)freeList;  
  for(size_t   i   =   0;   i   <   items   -   1;   i++)   {  
  *(void**)tmp   =   tmp   +   sizeof(T);  
  tmp   +=   sizeof(T);  
  }  
  *(void**)tmp   =   NULL;  
  }  
   
  哪位大大能够解释一下啊,为什么要用*(void**)tmp啊? 问题点数:100、回复次数:13Top

1 楼wiali(维埃里)回复于 2005-07-01 17:06:30 得分 0

还有为什么要*(void**)tmp   =   tmp   +   sizeof(T);这句话,难道是给temp指针里的内容赋值吗,但是又不像啊,这是搞不懂啊  
  Top

2 楼megaboy(飞天御剑流之杀神一刀斩)回复于 2005-07-01 18:09:33 得分 0

*(void**)tmp就是(void   *)tmp,是把本来是字符指针的tmp变为通用指针,我觉得代码的作者这样写是多余的,直接void*就行了。Top

3 楼wiali(维埃里)回复于 2005-07-01 18:38:03 得分 0

那么*(void**)tmp   =   tmp   +   sizeof(T);岂不和tmp   +=   sizeof(T);   一样了吗?  
  Top

4 楼yhbttfile(小兵)回复于 2005-07-01 20:04:25 得分 90

*(void**)tmp   =   tmp   +   sizeof(T);  
  就是给内容赋值,设置为下一个对象的起始地址。  
  (void**)tmp强制转换为一个地址的地址(把tmp的值强制转换一个指针的指针,提取(*符号)操作符以后就是数组的实际位置了)。  
  *操作符比较特殊,再仔细理解一下,应该可以知道是怎么回事情。  
   
  这个函数写得有问题。  
  申请的内容怎么传递出去?  
  第二次调用该函数以后,上次调用申请的内存不是就内存泄漏了?Top

5 楼firstdreamer()回复于 2005-07-01 20:18:05 得分 0

*(void**)tmp   =   tmp   +   sizeof(T);应该与(void   *)tmp一样,就是指针后移sizeof(T)个位置。Top

6 楼firstdreamer()回复于 2005-07-01 20:19:24 得分 0

不会,瞎说了,关注!Top

7 楼wiali(维埃里)回复于 2005-07-01 20:23:19 得分 0

这个函数绝对没有问题,我马上就贴该类的全部代码Top

8 楼wiali(维埃里)回复于 2005-07-01 21:23:30 得分 0

整个类太长了,我就不贴了,我认为   yhbttfile(小兵)   回答的对的,就是在把temp的第一个4个字节(因为提出的地址是void*类型,也就是4个字节)里放上下一个temp指针的值,这样就相当于一个链表,如果大家没有什么异议的话,我准备结贴给yhbttfile(小兵)分了!Top

9 楼cqpp()回复于 2005-07-02 09:35:02 得分 0

在tmp所指的位置放tmp+sizeof(T)也就是自己数据的起始位置,有错了吗?Top

10 楼zhouhuahai(道号"虚无")回复于 2005-07-02 10:44:35 得分 10

我的疑问:  
  1.模板参数T不在函数的参数表中,那么怎样调用这个函数呢?难道要这样写:  
  <int>   grow();?  
  2. 申请的内容怎么传递出去?  
  *(void**)tmp   =   tmp   +   sizeof(T);  
  tmp   +=   sizeof(T);//这里把tmp往后移了两次sizeof(T)的位置,那么总的来说,岂不是移了(items   –   1)*2*sizeof(T)个位置了?这样不是越界了么?  
   
  to-->yhbttfile(小兵)  
  第二次调用该函数以后,上次调用申请的内存不是就内存泄漏了?  
   
  我认为不会有这种现象,因为它是static变量.相同的函数调用只会进行一次初始化.Top

11 楼jackyshaw()回复于 2005-07-02 10:59:09 得分 0

为什么要*(void**)tmp   =   tmp   +   sizeof(T)这样呢?是不是有特殊的意义,或是增强安全性?  
  可以肯定地说,其实实际上和tmp+=sizeof(T)是没有区别的!  
  Top

12 楼yhbttfile(小兵)回复于 2005-07-02 13:58:14 得分 0

to-->yhbttfile(小兵)  
  第二次调用该函数以后,上次调用申请的内存不是就内存泄漏了?  
   
  我认为不会有这种现象,因为它是static变量.相同的函数调用只会进行一次初始化.  
  ——————————————————————————————————————  
  To   zhouhuahai(大草原):  
  你说的是对的。  
   
  不过,另外的疑问楼主也说了,可能与具体的实现相关。我们就只关注他的问题吧。  
   
  另,关于静态变量,我又去研究了一下,把知道的东西说出来,大家看看是否正确。  
   
  先写一个简单的函数:  
  int*   grow()    
  {  
  static   int   *pi   =   new   int;  
  return   pi;  
  }  
   
  编译成汇编语言:  
  int*   grow()    
  {  
  00416D10     push                 ebp      
  00416D11     mov                   ebp,esp    
  00416D13     push                 0FFFFFFFFh    
  00416D15     push                 offset   __ehhandler$?grow@@YAPAHXZ   (43D59Eh)    
  00416D1A     mov                   eax,dword   ptr   fs:[00000000h]    
  00416D20     push                 eax      
  00416D21     mov                   dword   ptr   fs:[0],esp    
  00416D28     sub                   esp,0CCh    
  00416D2E     push                 ebx      
  00416D2F     push                 esi      
  00416D30     push                 edi      
  00416D31     lea                   edi,[ebp-0D8h]    
  00416D37     mov                   ecx,33h    
  00416D3C     mov                   eax,0CCCCCCCCh    
  00416D41     rep   stos         dword   ptr   [edi]    
  static   int   *pi   =   new   int;  
  00416D43     mov                   eax,dword   ptr   [$S1   (44A244h)]    
  00416D48     and                   eax,1    
  00416D4B     jne                   grow+73h   (416D83h)    
  00416D4D     mov                   eax,dword   ptr   [$S1   (44A244h)]    
  00416D52     or                     eax,1    
  00416D55     mov                   dword   ptr   [$S1   (44A244h)],eax    
  00416D5A     mov                   dword   ptr   [ebp-4],0    
  00416D61     push                 4          
  00416D63     call                 operator   new   (415CA8h)    
  00416D68     add                   esp,4    
  00416D6B     mov                   dword   ptr   [ebp-0D4h],eax    
  00416D71     mov                   eax,dword   ptr   [ebp-0D4h]    
  00416D77     mov                   dword   ptr   [pi   (44A240h)],eax    
  00416D7C     mov                   dword   ptr   [ebp-4],0FFFFFFFFh    
  return   pi;  
  00416D83     mov                   eax,dword   ptr   [pi   (44A240h)]    
  }  
   
  其他地方我们就不关注了,如果要仔细研究,可以看看atexit等C程序库的相关知识。我们就关注这个变量初始化部分。  
  00416D43     mov                   eax,dword   ptr   [$S1   (44A244h)]    
  00416D48     and                   eax,1    
  00416D4B     jne                   grow+73h   (416D83h)    
  上面几句相当于:  
  if(__initialized   ==   1)  
      goto   416D83h;  
  地址416D83h是什么内容?  
          00416D83     mov                   eax,dword   ptr   [pi   (44A240h)]    
  函数的最后一行。  
  也就是说,如果函数已经调用过一次,则直接返回pi。  
   
  否则,如果函数从没调用一次就做如下操作:  
  00416D4D     mov                   eax,dword   ptr   [$S1   (44A244h)]    
  00416D52     or                     eax,1    
  00416D55     mov                   dword   ptr   [$S1   (44A244h)],eax    
  00416D5A     mov                   dword   ptr   [ebp-4],0    
  00416D61     push                 4          
  00416D63     call                 operator   new   (415CA8h)    
  00416D68     add                   esp,4    
  00416D6B     mov                   dword   ptr   [ebp-0D4h],eax    
  00416D71     mov                   eax,dword   ptr   [ebp-0D4h]    
  00416D77     mov                   dword   ptr   [pi   (44A240h)],eax    
  00416D7C     mov                   dword   ptr   [ebp-4],0FFFFFFFFh    
  return   pi;  
  00416D83     mov                   eax,dword   ptr   [pi   (44A240h)]    
   
  其中:  
          00416D63     call                 operator   new   (415CA8h)    
  就是申请内存。  
  看来,的确只声请了一次。  
   
  上面这些内容可能很罗嗦。只要仔细研究一下C++的静态变量的说明就可以明白。本人只是想佐证一下而已。也多谢“zhouhuahai(大草原)”的认真,才有我的认真。。。  
  Top

13 楼wiali(维埃里)回复于 2005-07-02 21:23:03 得分 0

to-->yhbttfile(小兵)  
  果然是严谨,pfpf!  
  放在这里给大家学习一下,明天结贴!Top

相关问题

  • 分配内存???
  • socket编程时,一些函数自动分配得内存如何释放?
  • 函数体内数组分配的内存会自动释放吗,
  • 请教:不靠库函数来分配和释放内存,JAVA可以自动的对内存进行管理。能详细说明吗?
  • CFileDialog 的内存分配
  • 类的内存分配
  • 内存分配的问题
  • 内存分配的问题!
  • 变量的内存分配
  • 内存分配的问题

关键词

  • 函数
  • 内存
  • ca
  • 内容
  • 调用
  • 变量
  • dword ptr
  • yhbttfile
  • grow
  • eax

得分解答快速导航

  • 帖主:wiali
  • yhbttfile
  • zhouhuahai

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo