In the traditional C language, we check the return value of the function to determine whether the call is successful and handle various exceptions. In the Unix environment, we can set the error variable to send an error message and use setjmp, longjmp. The C ++ language introduces the exception mechanism. When an exception occurs, the program module can throw an exception. Other methods can catch this exception through try catch. However, compared with the later Exception Handling Mechanism in Java and C #, C ++ still has a lot to be improved:
1. The exception base class is missing. Any class can be thrown as an exception, and an object, reference, or pointer can be thrown.
2. There is no way to constrain the method like Java, and it is required to handle or throw all possible internal exceptions. For example, other program modules that call this method cannot determine from the interface whether it will throw an exception, so they will not be able to handle the exception.
Because of this, C ++ programmers seldom use its exception mechanism. I usually use the C language to differentiate errors by using the return values, sometimes an exception is occasionally used in the class constructor, because errors in the constructor may cause the generated object to be abnormal, and the constructor has no return value, so an exception can only be thrown, or set a status flag.
In addition, a major drawback of the exception Mechanism in C ++ is that it may cause resource leakage, for example:
Void F ()
{
Resource * r = new resource ();
File * f = fopen(“datafile.txt ");
Dosomething (); // an exception may be thrown here, causing the code to be executed and the resources to be released in time.
Delete R;
Fclose (f );
}
In order to solve the problem of resource leakage, it is not only caused by exceptions, but may also be caused by accidental direct return in some places during programming, or to avoid adding a statement such as delete, fclose before each returned statement. Here we need to use the C ++ raiI mechanism:
RaiI: Resource acqusition is initialization resource application is initialized
The principle of utilization is that the Destructor is automatically called when the objects on the stack exit the scope. Therefore, we can directly apply for resources in the constructor, release resources in the destructor to ensure that resources are always released normally.
For example:
Class File
{
Public:
File (const char * file_name) {f = fopen (file_name );....}
~ File () {fclose (f );}
Int write (const char * data, int Len );
Int read (char * data, int Len );
PRIVATE:
File * F;
}
In addition, STD: auto_ptr is constructed based on this principle.
Another point to note is that some people prefer to leave the Resource Initialization blank in the constructor and use other methods to apply for resources separately, for example, if f = NULL is set in the above file constructor and an open () method is added to open the file, I personally think this is unnecessary because, in the write and read methods, you must determine whether F is not null every time. For specific applications, C # and Java seem to have many constructors that do nothing by default.