C++-为什么C++没有finally

引入

看下面这段代码:

1
2
3
4
5
6
7
8
9
try
{
File *file = fopen("123.txt","rw+");
// do something...
}
catch(const Exception &e)
{
// do something for exception...
}

当在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;
}
// do something...
return true;
}
catch(const FileConstructionError &e)
{
// 使用RAII当发生异常时自动调用析构函数,不会出现内存泄漏
LOG("File Construction Error");
return false;
}
}

总结

C++使用RAII来替代Javafinally函数。在一个系统中,需要为每一个资源都使用一个资源句柄类。无论如何,我们不需要为每一个资源获得都写出finally语句。在实时系统中,资源获得要远远多于资源的种类,因此和使用finally构造相比,资源获取即初始化技术会产生少得多的代码。