1,问题
写代码的时候遇到一个问题,在方法类里面有个成员变量IplImage* resultImageToDisp,在主函数里面有个局部变量IplImage* resultImage,我需要将resultImageToDisp赋值给resultImage,但只是浅拷贝,就是说resultImageToDisp和resultImag两个图像指针指向了同一内存,主函数结束时按惯例使用cvReleaseImage(&resultImage),但是在退出函数体时候调用方法类的析构函数,此析构函数也存在一个cvReleaseImage(&resultImageToDisp),这样就造成同一内存释放两次报错。本来简单以为在析构时添加一个if(resutlImageToDisp!=NULL)判断语句就可以解决问题,可是还是报错。那么问题来了,NULL的作用是什么,此处添加什么判断语句可以解决问题?
2,抽象
char *c1,*c2;
c1=new char[10];
c2=c1;
delete c1;
if(/* c2指向的内存空间没有被释放 */)
{
delete c2;
}
该问题抽象成以上一段代码,即寻找if判断语句。
3,思路
首先,我想到的是判断指针是否为NULL。由于没能真正理解NULL的作用,想当然认为判断指针是否为NULL,就是判断该指针指向的内存是否为0,这是错误的理解。经过测试,我对同一指针加上NULL判断可以通过,如以下代码。
if (ROIImageUnsmoothed!=NULL)
{
cvReleaseImage(&ROIImageUnsmoothed);
}
if (ROIImageUnsmoothed!=NULL)
{
cvReleaseImage(&ROIImageUnsmoothed);
}
resultImage=resultImageToDisp;
cvReleaseImage(&resultImage);
if (resultImageToDisp!=NULL)
{
cvReleaseImage(&resultImageToDisp);
}
第一次if成立,第二次不成立,代码完全没问题。而对于双指针指向同一内存却报错,说明,NULL只是判断指针本身,而不是它的内存。
查阅资料才明白,释放内存,如free(),deleate(),只是做了一件事情:斩断指针变量与这块内存的关系。(我觉得应该是将这块内存交还给系统,不再供程序使用)free函数就是把这块内存和指针之间的所有关系斩断。从此指针和那块内存之间再无瓜葛。至于指针变量本身保存的地址并没有改变,但是它对这个地址处的那块内存却已经没有所有权了。那块被释放的内存里面保存的值也没有改变,只是再也没有办法使用了。更斩草除根的办法是释放后马上悬空地址,即将指针置为NULL:将指针保存的地址清除,使其不指向任何内存。
这样可以解释,opencv的cvReleaseImage函数,一定包括释放内存和指针悬空两个过程。释放掉resultImage后,该指针指向的内存已经不存在,但是并不影响resultImageToDisp,它任然是一个非NULL的指针,所以if判断语句会失败,而且它的指向内存已经不存在,所以再次释放会报错。
最后,再次查阅资料,发现没有什么好的方法可以处理,囧。。。
4,收获
养成好的习惯,指针变量创建时初始化,要么将指针设置为NULL,要么让它指向合法的内存。
指针指向的内存被释放后,紧接着将指针置为NULL。
别用两个指针指向同一内存这种邪恶的东西。
参考:
http://bbs.csdn.net/topics/80162678
http://www.cnblogs.com/haore147/p/3647437.html