引入
看下面这段代码:
1 2 3 4 5 6 7 8 9
| try { File *file = fopen("123.txt","rw+"); } catch(const Exception &e) { }
|
当在do something
过程中,发生异常,则会出现file
未关闭而导致内存泄漏的情况。在Java
中,有一个finally
函数可以在此情况后调用。而在C++
中,如何去避免这种情况呢?
解决
C++
中,通常使用RAII(Resource Aquisition is Initialization)
资源获取即初始化。
就是将资源封装成一个类,将资源的初始化过程封装在构造函数内,释放封装在析构函数中。要在局部使用这个资源时,就实例化一个local variable
,当抛出异常时,离开作用域自动调用其析构函数,保证资源的释放。
如下示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| class FileGuard { public: FileGuard(string path, string rw) { file = fopen(path, rw); } ~FileGuard() { if(file) { fclose(file); delete file; } } FILE* operator()() { return file; } bool IsVaild() { return static_cast<bool>(file); } private: FILE *file; }
bool OpenFile() { try { FileGuard fileGuard("1.txt","rw+"); if(!fileGuard.IsVaild()) { throw FileConstructionError; } return true; } catch(const FileConstructionError &e) { LOG("File Construction Error"); return false; } }
|
总结
C++
使用RAII
来替代Java
的finally
函数。在一个系统中,需要为每一个资源都使用一个资源句柄
类。无论如何,我们不需要为每一个资源获得都写出finally
语句。在实时系统中,资源获得要远远多于资源的种类,因此和使用finally
构造相比,资源获取即初始化
技术会产生少得多的代码。