new出的对象数组必须要用delete[]删除,而普通数组和结构数组delete和delete[]都一样_申请了一个对象数组后,释放时用delete而非delete []释放对象数组,结果是

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

如果你需要这些资料,可以戳这里获取

温馨提示:

该文所有测试没有特殊说明都是在Debug模式下!用的是VS2010编译器!

====================================================================================================================================

1.在释放堆栈中c++基本数据(包括int,char…结构体等)的存储空间时,不管是否是数组用delete都不会有错!而且能正常释放所有内存,不会导致内存泄露!

复制代码

//程序A 
struct text\_data\_t 
{ 
 int i; 
}; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
 text\_data\_t *pdata=new text_data_t[5]; 
 char *pi=newchar[5]; 
 for(int k=0;k<5;k++)
 pdata[k].i=k; 
 delete pdata; 
 delete pi; 
 //内存泄露检测函数。若检测到内存泄漏那么就会输出宽里输出?"Detected memory leaks!....等信息" 
 \_CrtDumpMemoryLeaks(); 
} 

复制代码

没有检测到内存泄露,于是乎,可以看出1是正确的!

2)对象数组不能用delete,只能用delete[];

首先我们需要知道:系统在释放对象数组时,会先执行数组内所有元素的析构函数,然后再调用void operator delete(void *pUserData),一次性将所有分配的数据空间释放!

复制代码

// 程序B 
class CTextClassA 
{
public:
 int m\_num;
 CTextClassA() { m\_num=0; };
 ~CTextClassA()    {  cout<<"~CTextClassA()"<<endl; } 

 void SetNum(int n)    {   m_num=n; } 
}; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
 CTextClassA *pa=new CTextClassA; 
 CTextClassA *pas=new CTextClassA[5]; 
 CTextClassA *pas_arr[5]; 
 for(int i=0;i<5;i++) 
 { 
 pas[i].SetNum(i); 
 pas\_arr[i]=&pas[i]; 
 cout<<"pas"<<i<<":"<<pas[i].m_num<<"\t"; 
 } 
 delete pa; 
 delete pas; 
} 

复制代码

输出结果

调试运行到delete pas;出现保护错!

在release下运行,没有出现上面那个错误提示窗口!但是输出结果是一样的!数组里5个对象只有第一个对象,运行了析构函数!事实证明2的断言同样也是正确的!OK!

====================================================================================================================================

那么我就要问了,

delete 结构体数组----都不会出问题!而delete 对象数组----报错。为什么呢???

如果你深深的被这个疑问所困恼,那么接下来让我们一起来解放这个疑惑!这个痛苦!

有些人有这样的误解:

我在网上看了很多帖子,很多人说,程序B:delete  pas;只释放了pas[0]其他的都没有释放;因为根据程序运行结果,我们可以看出,他只调用pas[0]的虚构函数!那么你怎么看呢?你觉得呢?

有人认为可以如下来释放数组所有空间:

//程序C: 
CTextClassA *pas=new CTextClassA[5]; 
for(int i=0;i<5;i++) 
{ 
 delete pas[i]; 
} 

那么你,怎么看待程序C;你觉得这样子可以吗?答案你自己去需找!看看运行结果你就会知道!异或是看完全文,那么你也会明白!

Ok!debug模式运行程序B,弹出上面错误提示框!按下重试,进入出错函数里

复制代码

void operator delete(void *pUserData) 
{
 \_CrtMemBlockHeader * pHead;
 TCCALLBACK(\_RTC\_Free\_hook, (pUserData, 0));

 if (pUserData == NULL)
 return;

 /\* block other threads \*/
 \_mlock(\_HEAP\_LOCK); 
 \_\_TRY

 /\* get a pointer to memory block header \*/
 pHead = pHdr(pUserData);

 /\* verify block type \*/
 \_ASSERTE(\_BLOCK\_TYPE\_IS\_VALID(pHead->nBlockUse));    //程序中断处,按F11进入不了函数内部!那怎么办呢,从数据pHead入手 
 
 \_free\_dbg( pUserData, pHead->nBlockUse );
 \_\_FINALLY
 \_munlock(\_HEAP\_LOCK); /\* release other threads \*/
 \_\_END\_TRY\_FINALLY
 
 return; 
} 

复制代码

Google找到pHead 的类型CrtMemBlockHeader数据结构的解释 参考资料

1) http://msdn.microsoft.com/en-us/library/bebs9zyz(v=vs.71).aspx

2) http://hi.baidu.com/6908270270/blog/item/46b854248e0992358644f928.html#0

复制代码

typedefstruct \_CrtMemBlockHeader 
{ 
  // 指向前一块数据块的指针 
  struct _CrtMemBlockHeader *pBlockHeaderNext; 
  // 指向下一块数据块的指针 
    struct _CrtMemBlockHeader *pBlockHeaderPrev; 

 // File name:请求内存分配操作的那行代码所在的文件的路径和名称,但实际上是空指针 
    char *szFileName; 
 // Line number:行号,请求内存分配操作的那行代码的行号 
    int nLine; 

 // 请求分配的大小  
 size\_t nDataSize; 

 // Type of block 类型 
    int nBlockUse; 
 // 请求号 
    long lRequest; 
 // 这个数据是干嘛的呢,查下单词gap是什么意思,你就知道了! 
    unsigned char gap[nNoMansLandSize];
} \_CrtMemBlockHeader; 

复制代码

这里解释下Gap[]吧:

前后各有4个字节的 gap[],前后的gap都为 0xFD.

如果你在自己的Data里写, 不小心越了界(前面或者后面), 系统在delete的时候通过检查 gap 的数据是否还为0xFD,就知道你有没有越界.

当然了, 如果你恰好写的都是0xFD, 那就没法知道了.

函数_CrtDumpMemoryLeaks();就是通过检查分配链表(pBlockHeaderNext和pBlockHeaderPrev为双链表的双链), 来查找是否有泄漏。

====================================================================================================================================

我搜索了很多量资料,做了很多实验,得出结论:

对于普通数据存储空间的分配形式:

公式1)_CrtMemBlockHeader + +gap[nNoMansLandSize];这类数据用delete和delete[]都一样!

通常我们的指针都是指向的首地址!

而对于对象数组则是:

公式2)_CrtMemBlockHeader +数组元素个数+ +gap[nNoMansLandSize];

举个例子说:

int *pis=new int[5];

当我们的程序执行到这么一条语句时,你觉得系统会给他分配多少内存空间,20?如果你的答案是20那么我可以告诉你,亲,你太单纯了,想得太简单了!那么请再仔细理解前面两个公式!

实际上系统分配sizeof(CrtMemBlockHeader)+20+sizeof(gap[nNoMansLandSize])大小的空间!

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

如果你需要这些资料,可以戳这里获取

-HWqyzXAh-1715891389428)]
[外链图片转存中…(img-zYYXyezc-1715891389428)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

如果你需要这些资料,可以戳这里获取

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值