Programming resource management (1)
First, the resources used in programming
When programming, a wide variety of resources are used, such as files, network connections, database connections, semaphors, events, threads, memory, etc. Here we also treat memory as resources. These resources are very precious, unlimited, no release, good programming habits should release these resources as soon as possible, and the following we discuss us to release them, and how to guarantee the release resources in the case of abnormalities.
Second, use the destructor in C
Direct release resources
The example code is as follows:
Void f (const char * fn)
{
// Open fn forreading
File * pfile = fopen (fn, "r");
// USE File
Use_file (pfile);
Fclose (pfile);
}
Here we omitted the processing logic of use_file. The logic of the function F is very simple, open the file, use the file, and finally close the file. If the USE_FILE function ends normally, everything is no problem, the resource is released, but if use_file throws an exception, the file will never close. If you want to fix this problem, the direct modifications are as follows:
Void f (const char * fn)
{
// Open fn forreading
File * pfile = fopen (fn, "r");
Try {
// USE File
Use_file (pfile);
}
Catch (...) {
Fclose (pfile);
}
Fclose (pfile);
}
You can see that such modifications introduced more code, and there are two free resource code (red code). This will be very painful if you use more resources in your function. Fortunately, C provides an elegant solution.
2. Using RAII usa
A conventional method in the C language is RAII (Resource Acquisition IS Initialization). The C language guarantees that the logging function of the local object will always be called regardless of how the function is exited. Its basic idea is to use local objects represent resources to release resources for the sect of local objects. This ensures that there is no resource leak, the resource is not released.
For the above problems, the solutions for C founders Bjarne Stroustroup are as follows:
Class file_handle {
File * p;
PUBLIC:
FILE_HANDLE (const char * n, const char * a)
{P = fopen (n, a); if (p == 0) throw open_ERROR (Errno);
FILE_HANDE (file * pp)
{P = PP; if (p == 0) throw open_error (errno);
~ File_handle () {fclose (p);
Operator file * () {returnit p;
// ...
}
Void f (const char * fn)
{
// Open fn forreading
File_Handle F (FN, "R");
// USE File Through F
Use_file (f);
}
This regardless of the functionality to exit, because of the exception, C guarantees the destructive function to call File_HANLLE, so that the file handle is turned off, regardless of the file handle. It can be seen that the code is clear, and it is more likely to understand and use, but safer. 3. An example of app:
1) The Auto_PTR class in the C standard library. Different, the resources here are memory. Exterior, Auto_Ptr cannot be used in containers in STL, and cannot use it to release the arrays from New.
2) The CComautocriticalSECTION class in the ATL, the constructor of the class is initialized the critical area object, and the destructive function releases the resources used by the critical area object.
3) Basic_ifstream, Basic_OFStream, etc. in STL, close the file handle and release resources when the destructor is analyzed.
Third, use the FINALLY clause in Java
Using Java language, programmers can indeed regardless of memory disclosure, memory overflow and other headaches. But for resources used in Java programming, such as files, database connections, network connections, etc., but also require programmers to explicitly release resources. The method used by the release resource is no longer a destructive function, but the try, finally statement.
Due to the difference between the memory model, the peer of the C destructor is provided in Java, and the Finalize method is provided. But the Finalize method is only called only when the GC is running. At this time, it may be a long time to release the resource. There is no need to occupy the resources, reducing the reliability and efficiency of the program. That is, the timing of using the Finalize method to release the resource is uncertain, and we need a certain way to release resources. So can't rely on the Finalize method to complete the work of the release of resources.
But Java provides the Try, FinalLla syntax structure to complete deterministic resource recycling. Language guarantees that the finally clause will always be performed, regardless of the TRY block because the abnormality exits or normal exits. (A little bit like She's __TRY, __ Finally syntax.) Finally clause and C destructor have similar functions.
Also implement the examples described above, the code is as follows:
Void f (String Fn) {
FileReader fr = new fileReader (fn);
Try {
// USE File
Use_file (fr);
} finally {
Try {
IF (fr)
Fr.close ();
}
Catch (ioexception) {}
}
}
Note that the TRY, CATCH statement is used in the Finally clause. Consider the following:
1 If the function f uses two resources: resource1, resource2.
2 If an abnormality occurs when the first resource is released.
3 Then lead to the code that releases the resource2 cannot be executed.
So to ensure that the second resource resource2 can be released, it must ensure that the exception is not thrown when the first resource resource1 is released. There is no longer, C also requires unusual to throw an abnormality in the destructive function. For details, please refer to [More Effective C Terms 11].
Fourth, discuss the DISPOSE mode in .NET, the USING statement, and the deterministic resource recycling in C / CLI.