Let's take a small code, it takes from Bjarne Stroustrup's speech "Speaking C as a native":
// Use an Object to represent a resource ("resource acquisition is initialization)
Class file_handle {// belovers in some support library file * p; public: file_handle (const char * pp, const char * r) {p = fopen (pp, r); if (p == 0) throw cannot_open (PP) } File_handle (const string & s, const char * r) {p = fopen (s.c_str (), r); if (p == 0) throw cannot_open (pp);} ~ file_handle () {fclose (P) } // deStructor // Copy Operations and access functions};
Void f (string s) {file_handle file (s, "r"); // use file}
Friends who are familiar with C will not be unfamiliar with this technique of referred to as RAII. Simply put, RAII's general practice is this: obtaining resources when the object constructs, then controls access to the resource, which is always valid in the life cycle of the object, and finally releases resources when the object destructor. Taking this, we actually host the responsibility of the management of a resource to an object. This kind of practice has two benefits:
First, we don't need to explicitly release resources. With the function f in the above code, we don't have to worry about "Forget" to close the file. Moreover, even if the control structure of the function f changes, for example, inserting Return in the middle, we can determine that this file will definitely be closed. Especially in "unusual full day", RAII is a powerful weapon for achieving an abnormal security. Similarly, if a class C contains a File_Handle member, we don't have to worry about the "Forget" to close the file when it is destroyed.
Second, in this way, the resources required for the subject are always valid during their life - We can say that this class maintains an invariant. In this way, when the resources are used through such objects, there is no need to check the problem of resource validity, simplify logic and improve efficiency.
Ok, introduced the Raii, the next role is the famous garbage collection (GARBAGE Collection, hereinafter referred to as GC). With Java's popularity, GC has been accepted by more and more people. Here I briefly introduce the operational mechanism of GC.
First introduced several terms: in the context of GC, the programs can be directly manipulated (for example, saved in a local variable or global variable), we call "root"; assume that the object A1 saves one Point points to the pointer of the object A2, the object A2 saves the pointer to the object A3, we call a "pointer" - of course, the pointer chain can be arbitrarily; assume some of the program Root departure, through a pointer chain to reach object A, then we think that object A is "survive", otherwise it is considered "death", ready to release the memory it occupies. All GC implementations, its operational mode is to check if the object is survive, and the object of death will be released, and its implementation mechanism is generally divided into three categories: 1. Reference Counting, this type of GC implementation is saved for each object Pointing to its number of pointers, once this number is reduced to 0, this object is released, the small nameless boost :: Shared_PTR is this way; second, mark-sweeping (Mark-Sweep), this type of GC implementation Periodically scan the entire heap, first mark the survival object, then release the remaining death objects; three, node replication (COPYING), this type of GC implementation will divide the entire pile into half, and periodically Move the survival object from the half of the current used to the other half, and stay in the original position is naturally abandoned. In these three types of implementations, the restrictions of reference counts (especially those that cannot be recycled), and generally in efficiency, less application, and there are many applications. Some details in this area can be referred to the garbage collection column on the first session of the program 2003. In addition, the People's Posts and Telecommunications Publishing House is about to launch the Chinese translation of the book "garbage collection", this book can be said to be the only monograph in the world about GC, and friends who are interested in GC can find a look ( Oh, hit an advertisement, ^ _ ^).
There is no doubt that for programmers, it must be very pleasant after allocating the memory. More importantly, programmers can bid farewell to suspension references and memory leaks - they are one of the most headaches in program development. Finally, with GC support, sharing data between the various modules of the program makes it easier, safer, and helps to simplify the interface between the modules. Although there is also a variety of doubts in terms of GC's efficiency, it must be recognized that GC is a valuable technology.
Unfortunately, very unfortunately, existing GC mechanisms and RAII can be said to be a water fire - how would this?
The crux is that the two attitudes are different from the parallelism function. Review We introduce RAII, its core content is to host a resource to an object, which allows resources to be active within the live cycle of the object, so that it requires resource to be released by the object's destructor. The problem is in that the current existing GC mechanism is difficult to provide support for the destructor. Some people may feel strange, let the GC do not call the destructor when the object is released? Unfortunately, things are not so simple.
In the context of the GC, the action on the destruction of the destruction is called "Finalization", and the support terminal has always been a problem with GC implementation, because the ending action is likely to collect jobs Bring big interference. For example, consider the following ending action (here I use the form of C destructor): Class Wedget {... ~ wedget () {// Global_Pointer is a global variable global_pointer = this;}};
Suppose now we have a Wedget object W, further assume that at a moment, the GC mechanism discovers from any root, you can't reach W, then follow the definition it has died, you can perform the end action and release it. However, when we perform the end action, W is assigned to a global variable to a global variable, which is a root from the root, which can reach the pointer chain, which is defined - - It is resurrected again! If you have your heart, you can think of many varieties in the above questions, some of which may also be very "crown".
What should we do this? Resurrection W? In that case, we must also resurrect all W points to the object, but it is difficult to achieve this, which requires us to release any object before performing the end action (which object you cannot know in advance), and may fall into death Cycle (after performing the end action, you must re-determine whether each object survive, and try to perform end action ...). So we don't resurrect W? Nor well, so global_pointer has become a suspension reference, and the security of GC guarantees is smashed with a big hole. Or let's prohibit the appearance of the pointer operation in the destructor? Difficult, if the destructor calls other functions, can you still be prohibited? Do you want to call other functions? Cough, then this destructor cannot achieve any substantive functions, do not release resources.
In addition to the difficulties of implementation, there is a more essential problem with the end mechanism in GC: the time to perform the end mechanism is unable to determine. It does not say that the GC implementation of the reference count has a considerable delay. Even if the future realization is really guaranteed to be released in the moment of death, it is also unable to meet the demand: assume that you want to hope at a moment Destructure an object, release it it possess, but as long as there is still a pointer to this object, this object will "tenacious". You may wish to assume that if the resource that needs to be released here is a network link for a timing fee, then ... (I wish you good luck, brother! This is your floor, ^ _ ^)
In summary, we have sufficient reasons. The existing GC environment is not possible to apply RAII, and the water is not allowed. In fact, the language of GC is supported like Java, usually does not encourage you to use the end mechanism, and the resources required by the object must be explicitly released. The simplest, add a CLOSE member function to this class to release resources.
What shortcomings do you have? In the initial introduction of RAII advantages:
First, all the resources needed by all objects must be explicitly manually released. Take the original example, the function f must be added with file.close (), and we have to start a change in the function F control structure, whether it is inserting Return or throwing an abnormal place, must be added File.close (). In response to this situation, the language such as Java generally supports this feature of Try ... Finally, which requires that the FINALLY code block must be invoked whether you leave the function due to what reason. Try ... finally did effectively alleviate this problem, but still not assessed the RAII program ideal: First, the effort to write try ... finally is unable to reuse, if you have 10 functions, file_handle You must write the same code 10 times; second, make sure that the resources applied in the TRY block and the release of resources in the Finally block are each matching now become programmers. This is a bookkeeping burden, and once an error occurs Resource leaks is very headaches - in general, this is more concealed than memory leaks, and it is impossible to have special tools; third, if a class has a number of members like file_handle, we must This class also adds a close function and calls a member's close function (not the function name of all members release resources), which is also a more bookkeeping burden - and try ... finally can't help What is too big. Secondly, since it is allowed to explicitly release the resources, the object cannot be maintained as the previously needed to maintain the resources in its life "such an invariant, so all the resources used in the object must detect the validity of the resource, the user You must also pay attention to whether resources are valid when you use objects (this error is presented in an abnormal form). This not only makes logic complex, but also more bookkeeping burdens - For each of the needs of resources, users must remember what is unusual to be invalid.
Hey ~~ So far, it seems that the situation is slightly frustrated. RAII is a tool for managing resources, and the convenience and security of GC is more attractive, but both parties are not available. You either turn to the gc's embrace, then you have to manually manage other resources, tolerate more troubles and bookkeeping burden; or give up GC, honestly manually manually manage memory, but can enjoy RAII when managing other resources And safety. You can of course be said that the world is like this, sometimes we have to make a weigh, in order to get some and give up other, just ... Is there a better way?
Hey! Hey! Snapped!
I want to know what happen, and listen to the decomposition!