常见动态内存错误---内存泄漏 .

常见动态内存错误

编译器不能自动发现动态内存错误,动态内存错误通常只能在程序运行时才能被捕捉到,而且错误原因不容易查找,错误本身也不容易捕捉,改错难度较大。



1.动态内存分配失败却继续操作
内存不足等有可能导致动态内存分配失败,所以使用new请求分配动态内存后一定要检查返回地址是否为NULL。
如用if(p==NULL) 或 if(p!=NULL)进行检查,未检查前不要操作动态内存空间。


2.动态内存空间未初始化就进行读操作
C++标准并未规定动态内存空间的默认值,程序无法预知该默认值的具体指。因此,未经初始化的动态内存空间可能持有一个不确定的值。
所以申请分配动态内存空间的同时,要初始化该动态内存空间,尽量不要使用系统默认值。


3.动态内存空间越界使用
指针的功能虽然很强,但它容易指向错误的地方。当指针指向不正确的数据类型时,指针操作就会出错。
尤其是当指针指向一个数组时,很容易越界,造成错误。


4.内存泄漏
内存泄漏是一种比较严重的动态内存错误。程序长时间运行最终可能导致内存耗尽,运行速度变慢甚至系统奔溃。
例如:new与delete使用不配对,就可能导致new的空间未被delete。
使用new运算符申请分配的内存空间使用完后,一定要记得使用delete释放,且new形式要与delete对应。


5.继续使用已经释放了的动态内存空间
执行delete后,相应的指针变量的值未被改变,它依然指向原来的动态内存空间,只是原来动态内存空间的内容已经毫无意义了。

所以在执行delete之后,通常要将指针变量的值置成NULL,以免对内存空间进行误操作或者无效操作。


下面具体讲讲内存泄漏:


内存泄漏

指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。
内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。 


下面举几个例子:

1.下面a先是申请了一个int型的动态内存空间,初始化值为12,后面a又申请了一个int型空间,初始化值为34,
则第一次存储12的空间就不会被释放,并且存储12的空间没有被释放,也不能被使用了,造成了内存泄漏。

  1. #include<iostream>   
  2. using namespace std;  
  3.   
  4. int main()  
  5. {  
  6.     int *a=new int (12);  
  7.   
  8.     cout<<*a<<endl;  
  9.              //需要 delete a;   
  10.     a=new int (34);  
  11.   
  12.     cout<<*a<<endl;  
  13.   
  14.     delete a;  
  15.   
  16.     system("pause");  
  17.     return 0;  
  18. }  
#include<iostream>
using namespace std;

int main()
{
	int *a=new int (12);

	cout<<*a<<endl;
	         //需要 delete a;
	a=new int (34);

	cout<<*a<<endl;

	delete a;

	system("pause");
	return 0;
}
2.下面的函数,当调用时,会在动态内存中创建一个char型数组,并在桟中生成一个char型指针变量pChar,用pChar指向该数组。
当F调用结束时,pChar会自动消失,因为它位于桟区中,是局部变量;
而长度为100的动态内存空间中的字符串数组却依然存在,没有释放。
所以退出F()后内存就泄漏了,而且每次调用都会造成新的泄漏。
  1. void F(void)  
  2. {  
  3.     char *pChar=new char [100];  
  4.     //do something   
  5. }  
void F(void)
{
	char *pChar=new char [100];
	//do something
}
最好的做法就是:

  1. void F(void)  
  2. {  
  3.     char *pChar=new char [100];  
  4.     //do something   
  5.   
  6.     delete []pChar;  
  7. }  
void F(void)
{
	char *pChar=new char [100];
	//do something

	delete []pChar;
}

3.出现以下问题呢?

  1. //F返回一个指针,指向一个动态分配的对象   
  2. int *F(T arg)  
  3. {  
  4.    return new int [arg];//调用者负责释放此内存   
  5. }  
//F返回一个指针,指向一个动态分配的对象
int *F(T arg)
{
   return new int [arg];//调用者负责释放此内存
}

返回指向动态内存的指针的函数给其调用者增加了一个额外的负担--- 调用者必须记得释放内存


4.delete只提供了有限的保护

看下面的例子:

执行delete后,相应的指针变量的值未被改变,它依然指向原来的动态内存空间,只是原来动态内存空间的内容已经毫无意义了。
所以在执行delete之后,通常要将指针变量的值置成NULL,以免对内存空间进行误操作或者无效操作。

但是,

  1. int *p=new int (42);  
  2. auto q=p;  
  3. delete p;  
  4. p=NULL;  
int *p=new int (42);
auto q=p;
delete p;
p=NULL;

p和q指向相同的动态分配的对象,我们delete此内存,然后将p置为NULL,指出它不再指向任何对象。但是,重置p对q没有任何作用,在我们释放p所指向的(同时也是q所指向的)内存时,q也变得无效了。在实际系统中,查找指向相同内存的所有指针是异常困难的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值