// 1: if an exception is thrown in the constructor, the system will not execute the constructor for this object !!!
// 2: An exception is thrown in the constructor. if the object is created in the heap, the memory will be deleted. However, the delete operation will no longer call the destructor.
// 3: After an exception is thrown, the code after the exception statement is no longer executed, but the compiler will first put the internal members of the class (which has been constructed to love) after calling the destructor, jump out of try ()
// 4: each exception must be surrounded by a corresponding try, including an explicit manual exception. eg throw int (),
It also includes unknown exceptions during code execution, such as exceptions in. eg. string in MakeXML.
Similarly, each exception must have a catch () to capture it.
//: Each catch must have at least one type. It is also a universal type such as catch (...).
// If catch does not catch the exception thrown by try, the unhandle exception occurs.
: When an exception occurs but is not processed, the released release program will. After running, no results will be displayed. Close the program directly and no prompt will be displayed ,!!!!, How terrible it is to let you find a bug when this situation is discovered !!!
When published as debug, a dialog box similar to assertion failure is displayed, such as an unhandled exception.
1. Guidelines
Based on the reader's suggestions and reflections, I partially corrected the principles stated in Part14:
L as long as possible, use the constructors without throwing exceptions to the base class and member sub-objects.
L do not throw any exceptions from your constructor.
This time, I will think about the reader's opinions, the wisdom of the C ++ Xianzhi, and my new understanding and improvement. They are then translated into guidelines to clarify and extend those initial principles.
(Keyword Description: I use "sub-objects" or "inclusion objects" to represent elements in the array, unnamed base classes, and famous data members; use "inclusive objects" to represent arrays, derived class objects, or objects with data members .)
1.1 essence of C ++
You may think that when a constructor encounters an error, it will throw an exception to properly prevent constructor behavior of inclusive objects. Herb Suter wrote in a private letter:
The life cycle of an object begins with the completion of construction.
Inference: an object never exists when its construction is not completed.
Inference: the only way to report a constructor failure is to exit the constructor with an exception.
I guess you are doing something that is conceptually wrong ("wrong" is because it does not conform to the essence of C ++), and that is exactly why it is difficult to do.
"The essence of C ++" is mainly based on the myth of C ++ taught orally. It is our initial rule, derived from the ISO standard and the truth. Without such a library of C ++, chaos will govern the world. Given that no actual canon for the Spirit exists, confusion reigns over what is and is not within the Spirit, even among presumed experts.
One of the essence of C and C ++ is "trust the programmer ". As I wrote to Herb:
In the end, my "perfect" view was that the system designer had chosen to map exceptions to other forms during error propagation. This is not always the best, but it should be done. The strongest and weakest part of C ++ is that you can deviate from the preferred method you actually need. There are other dangerous behaviors that are permitted by language, depending on whether you know what you are doing. In the end, my "perfect" objective was to map exceptions to some other form of error propagation shoshould a designer choose to do so. not that it was always best to do so, but that it cocould be done. one of the simultaneous strengths/weaknesses of C ++ is that you can deviate from the preferred path if you really need. there are other dangerous behaviors the language tolerates, under the assumption you know what you are doing.
C ++ standards often tolerate or even permit potential unsafe behaviors, but not on this issue. Obviously, it is agreed that the programmer's judgment should be subject to a higher level of purpose (Apparently, the desire to allow programmer discretion yields to a higher purpose ). Herb found this high-level purpose in the second form of expression of the essence of C ++: an object is not a real object (and therefore is unavailable ), unless it is fully constructed (meaning that all its elements are fully constructed ).
Take a look at this example:
Struct X
{
A;
B B;
C c;
Void f ();
};
Try
{
X x;
X. f ();
}
Catch (...)
{
}
Here, A, B, and C are other classes. Assume that the construction of x. a and x. B is complete, and an exception is thrown during the construction of x. c. As we can see in the previous sections, the sequence of language rules is as follows:
L x constructor throws an exception
L The destructor of x. B is called.
L The destructor of x. a is called.
L control to the exception handling function
This rule conforms to the essence of C ++. X. c has never been constructed as an object. As a result, x has never been an object, because one of its internal members (x. c) has never existed. Because no object exists, there is no need for formal analysis.
Now let's assume that the constructor of x does not know how to control the initial exception. In this case, the execution sequence will be:
L x. f () called
L The destructor of x. c is called.
L The destructor of x. B is called.
L The destructor of x. a is called.
L x destructor called
L control skips the exception handling function and goes down
The exception will allow you to parse objects (x. c and x) that have never been fully constructed ). This creates a self-contradiction: A dead object has never been generated. The language structure avoids this conflict by forcing constructors to throw an exception.
The ghost of 1.2 C ++
It indicates that an object exists only when its members are fully constructed. But is it true that an object is equivalent to being fully constructed? In particular, the Construction Failure of x. c is "always" so bad that x must die before it is actually generated?
Before an exception occurs in the C ++ language, the definition process of x must be successful, and the call of x. f () will be executed. Instead of throwing an exception, we will call a status detection function:
X x;
If (x. is_ OK ())
X. f ();
Or use a return status parameter:
Bool is_ OK;
X x (is_ OK );
If (is_ OK)
X. f ();
At that time, we somehow did not emphasize the failure of constructing sub-objects such as x. c: such objects have never existed. At that time, the design was really so wrong (and we will never allow it now )? Is the essence of C ++ really different at that time? Or have we ever thought that x has never been formed or existed in our dreams?
To be fair, this problem is a little too much, because the C ++ language is no longer the same as it used in the past. Consider the old (previously supported exceptions) C ++ as the current C ++ as C ++. Although they have the same syntax, their semantics is different. Take a look:
Struct X
{
X ()
{
P = new T; // assume new fails
}
Void f ();
};
X x;
X. f ();
Assume that the new statement does not successfully allocate a T object. Exceptions support the calling of new return NULL, x constructor, and x. f () in the previous Compiler (or the modern compiler that disables exceptions. However, if the exception is allowed, a new exception is thrown, x construction fails, and x. f () is not called. The same Code has different meanings.
In the past, objects were not self-destructed. They must be constructed and dependent on us to discover their States. They do not process child objects that fail to be constructed. In addition, they do not call library functions that throw exceptions in the standard Runtime Library. In short, past and present programs exist in different worlds. We cannot expect them to always respond to the same errors.
1.3 is this your final answer?
I believe that the C ++ standard behavior is correct: the constructor throws an exception to parse the objects being processed and their inclusion objects. I don't know the exact reason why the C ++ Standards Committee formulated this behavior, but I guess:
L partial constructed objects will lead to some subtle errors, because the user's assumption of their construction degree exceeds the actual. Different objects of the same class will have unexpected and unpredictable behavior.
L The Compiler requires additional records. When a partially constructed object disappears, the compiler should avoid calling the Destructor on it and its sub-objects.
L The equivalence relationship between the constructed object and the object will be broken, undermining the essence of C ++.
1.4 guidance to the target user
An exception is part of an object interface. If possible, prepare the exception set that may be thrown by the interface in advance. If an API does not provide an exception specification statement and cannot be known elsewhere