文章目录
- 1、Terms9:利用destructors避免泄露资源
- 1.1代码1.0
- 1.2代码2.0
- 1.3代码3.0
- 2、总结
- 3、参考
1、Terms9:利用destructors避免泄露资源
假设我正在为小动物收容所编写软件,每天收容所建立一个文件,包含当天它所管理的收容动物的资料信息,我所要做的就是读出这些文件然后对每个收容动物进行适当的处理。
举个栗子:
class ALA{
public:virtual void processAdoption()=0;...
};
class Puppy:public ALA{
public:virtual void processAdoption();...
};
class Kitten:public ALA{
public:virtual void processAdoption();...
};
为了完成处理工作,需要你有一个函数从文件中读取信息,然后根据文件中的信息产生相应的实例对象。所以我们需要声明这样的函数。
1.1代码1.0
//从s中读取信息,然后返回一个指针
//指向新建立的某种类型对象
ALA* readALA(istream& s);
程序的关键是processAdoption()函数,如下所示:
void processAdoptions(istream& dataSource){while(dataSource){ //在有数据的情况下,一直读取ALA *pa = readALA(dataSource); //得到动物pa->processAdoption(); //处理收容所的动物delete pa; //删除readALA返回的对象}
}
但是这份代码并不完美,如果代码执行到
pa->processAdoption();
抛出了一个异常怎么办,这样后面的程序都不会执行到,就会导致processAdoptions资源泄漏。因此需要在processAdoptions内部添加异常捕获。
1.2代码2.0
代码如下:
void processAdoptions(istream& dataSource){while(dataSource){ ALA *pa = readALA(dataSource); try{pa->processAdoption(); } catch(...){. //捕获所有异常delete pa; //避免内存泄漏throw; //当异常抛出时,传递异常给调用者} delete pa; //当没有资源泄露时,回收资源 }
}
使用try和catch对代码进行了一些小改动,为了保险写了双份清除代码:一个为正常的运行准备,一个为异常发生时准备。这种代码并不完美,看上去心烦而且难以维护,好像还存在着一点问题。
1.3代码3.0
上述代码还有改进空间,我们可以把总被执行的清除代码放入processAdoptions函数内的局部对象的析构函数里,这样可以避免重复书写清除代码。无论函数是如何退出的,函数返回时局部对象总是要被释放的。
具体做法就是用对象代替指针,当类指针对象被释放时,我们能让他的析构函数调用delete,其实就是智能指针(smart pointers),在这里可以不用智能指针,只需要一个pointer-like对象,在它离开生存空间时删除它所指向的对象。
代码如下:
template<class T>
class auto_ptr{
public:auto_ptr(T *p = 0):ptr(p){} //保存ptr,指向对象~auto_ptr() {delete ptr;} //删除ptr指向的对象
private:T *ptr;
};
void processAdaptions(istream& dataSource)
{while(dataSource){auto_ptr<ALA> pa(readALA(dataSource));pa->processAdoption();}
}
这个版本的processAdaptions做出了2点重要的改进:
(1)pa被声明为一个auto_ptr对象,而不是一个raw ALA*指针;
(2)在循环的结尾没有delete语句;
使用auto_ptr的思想是,用一个对象存储需要被自动释放的资源,然后依靠对象的析构函数来释放资源;这样的话不仅代码本身比较可靠,简单,而且日后维护起来也十分的方便。
2、总结
书山有路勤为径,学海无涯苦作舟
3、参考
《More Effective C++》