C ++ exception

Source: Internet
Author: User

# Include <iostream>
# Include <exception>
Using namespace STD;

Class
{
Public:
A ()
{
This-> M_a = 0;
This-> m_st = "";
}
// _ Declspec (nothrow)
Void FN (int I) Throw (string, INT)
{
Switch (I)
{
Case 1:
If (this-> m_st.empty ())
Throw exception ("string is empty ");
Break;
Case 2:
If (this-> M_a = 0)
Throw exception ");
Break;
Case 3:
Throw string ("string ");
Break;
Case 4:
Throw 10;
Break;
Default:
Throw 'a ';
Break;
}
Cout <"every thing is OK ";
}
Protected:
PRIVATE:
Int M_a;
String m_st;
};
Int _ tmain (INT argc, _ tchar * argv [])
{
A;
Try
{
A. FN (5 );
}
Catch (STD: exception & E)
{
Cout <E. What () <Endl;
}
Catch (string & S)
{
Cout <S <Endl;
}
Catch (Int & I)
{
Cout <"I:" <I <Endl;
}
Catch (char & C)
{
Cout <"C:" <C <Endl;
}
Catch (...
{
Cout <"í ò äüµäò ì %%%%%%%%%%%%%%× %/ N ";
}
Return 0;
}

The key: C ++ specification requires that the object thrown as an exception must be copied.

Even if the thrown object is not released, the object will be copied.

 

Clause 12: understand the difference between "throwing an exception" and "passing a parameter" or "calling a virtual function"
 

In terms of syntax, declaring a parameter in a function is almost the same as declaring a parameter in a catch clause:

Class widget {...};// A class.
// Not important here

Void F1 (widget W );// Some functions whose parameters are
Void F2 (widget & W );// Widget, widget &, or
Void F3 (const widget & W );// Widget * type
Void F4 (widget * PW );
Void F5 (const widget * PW );
Catch (widget W )...// Catch clauses used
Catch (widget & W )...// Capture exceptions. The exception type is
Catch (const widget & W )...// Widget, widget &, or
Catch (widget * PW )...// Widget *
Catch (const widget * PW )...

Therefore, you may think that throw an exception to the catch clause is basically the same as passing a parameter through function call. There are some similarities, but they are also very different.

Let's start with the similarities. The way to pass function parameters and exceptions can be to pass values, pass references, or pass pointers, which is the same. However, when you pass parameters and exceptions, the operation process to be completed by the system is completely different. The reason for this difference is: when you call a function, the control of the program will eventually return to the function call, but when you throw an exception, control will never return to the place where an exception is thrown.

There is a function where the parameter type is widget and an exception of the widget type is thrown:

  // A function that reads values from the stream to the widget
Istream operator> (istream & S, widget & W );
Void passandthrowwidget ()
{
Widget localwidget;
Cin> localwidget;// Pass localwidget to operator>
Throw localwidget;// Throw a localwidget exception
}

When passing localwidget to the function operator>, you do not need to perform the copy operation. Instead, point the reference type variable W in operator> to localwidget, any operations on W are actually applied to localwidget. This is very different from throwing a localwidget exception. The lcalwidget copy operation is performed no matter whether the exception is captured by passing the value or by capturing the reference (the exception cannot be captured by the pointer because the type does not match, that is to say, the copy of localwidget is passed to the catch clause. This must be done because when localwidget leaves the living space, its destructor will be called. If the localwidget itself (rather than its copy) is passed to the catch clause, this clause receives only a rendered widget, the "body" of a widget ". This is not usable. Therefore, the C ++ specification requires that the object thrown as an exception must be copied.

Even if the thrown object is not released, the object will be copied. For example, if the passandthrowwidget function declares that localwidget is a static variable ),

Void passandthrowwidget ()
{
Static widget localwidget;// The current static variable (static );
// Always exist until the end of the program

Cin> localwidget;// Run as before
Throw localwidget;// The localwidget
}// Perform the copy operation

When an exception is thrown, a copy of localwidget is still copied. This means that localwidget cannot be modified in the catch block even if exceptions are captured through reference; localwidget copy can be modified only. Forced copy of abnormal objects. This restriction helps us to understand the second difference between passing parameters and throwing an exception: throwing an exception is slower than passing parameters.

When an exception object is copied, the copy operation is completed by the object's copy constructor. This copy constructor is the copy constructor of the class corresponding to the static type of the object, rather than the copy constructor of the class corresponding to the dynamic type of the object (dynamic type. For example, the following modified passandthrowwidget:

Class widget {...};
Class specialwidget: Public widget {...};
Void passandthrowwidget ()
{
Specialwidget localspecialwidget;
...
Widget & RW = localspecialwidget;// RW reference specialwidget
Throw RW;// It throws a type of widget
// Exception

}

The exception object thrown here is a widget, even if RW references a specialwidget. Because the sta-tic type of RW is a widget, rather than a specialwidget. Your compiler does not reference a special-widget at all. The compiler must note the static type of RW ). This behavior may be different from what you expect, but it is consistent with the copying of constructors in C ++ in other cases. (However, there is a technology that allows you to copy objects based on the dynamic type of the object. For more information, see section 25)

An exception is a copy of another object. This fact affects how you can throw another exception in the Catch Block. For example, the following two catch blocks are the same at first glance:

Catch (widget & W)// Catch widget exceptions
{
...// Handle exceptions
Throw;// Throw an exception again to make it
}// Continue transmission
Catch (widget & W)// Catch widget exceptions
{
...// Handle exceptions
Throw;// Pass the caught exception
}// Copy

The difference between the two catch blocks is that the exception currently captured is thrown again in the first Catch Block, and a new copy of the currently caught exception is thrown again in the second Catch Block. If the system overhead for generating additional copies is ignored, are there any differences between the two methods?

Of course. The current exception is thrown again in the first block, no matter what type it is. Especially if this exception is thrown as the specialwidget type at the beginning, the special-widget exception is passed out in the first block, even if the static type of W is a widget. This is because the copy operation is not performed when an exception is thrown again. The second Catch Block throws a new exception. The type is always a widget, because the static type of W is a widget. In general, you should use throw to throw the current exception again, because it will not change the exception type passed out, and is more efficient, because there is no need to generate a new copy.

(By The Way, an abnormal copy is a temporary object. As explained in cla19, a temporary object can allow the compiler to optimize its lifetime (optimize it out of existence), but I think it is difficult for your compiler to do so because there are few exceptions in the program, therefore, compiler vendors will not spend a lot of effort on this .)

Let's test the following three catch clauses for capturing widget exceptions: the exception is thrown as passandthrowwidgetp:

Catch (widget W )...// Capture exceptions by passing values
Catch (widget & W )...// Capture by passing a reference
// Exception

Catch (const widget & W )...// Pass a reference pointing to the const
// Capture exceptions

We immediately noticed another difference between passing parameters and passing exceptions. An object thrown by an exception (a temporary object is always explained just now) can be captured through a common reference; it does not need to be referenced by a reference-to-const object) capture. A temporary object cannot be transferred to a non-const reference type parameter in a function call (see clause 19), but is allowed in an exception.

Let's get back to the abnormal object copy test regardless of the difference. We know that when passing function parameters by passing values, we create a copy of The passed object (see article 22 of Objective C ++ ), and store this copy to the function parameters. This is also the case when we pass an exception by passing values. When we declare a catch clause like this:

Catch (widget W )...// Capture by passing values

Two copies of the thrown objects will be created. One is a temporary object that must be created for all exceptions, and the other is to copy the temporary object to W. Similarly, when we capture exceptions through reference,

Catch (widget & W )...// Capture by reference
Catch (const widget & W )...// Also captured by reference

This will still create a copy of The thrown object: copy is a temporary object. On the contrary, when we pass function parameters through references, no object is copied. When an exception is thrown, the number of copies of the thrown object constructed by the system (which will be analyzed later) is one more than the number of copies constructed when the same object is passed to the function as a parameter.

We have not discussed how to throw an exception through a pointer, but it is the same as passing a parameter through a pointer. Either method is a copy of the pointer to be passed. You cannot think that the thrown pointer is a pointer to a local object, because the local variable has been released when the exception leaves the living space of the local variable. The catch clause returns a pointer to an object that does not exist. This behavior should be avoided during design.

The method used to pass an object from a function call to a function parameter is different from the method used to pass the object from an exception throw point to a catch clause. This is only one aspect of the difference between parameter passing and exception passing, the second difference is that the type matching process is different between the function caller or the thrown exception and the called or the caught exception. For example, the SQRT function in the standard Math Library:

Double SQRT (double );// From <cmath> or <math. h>

We can calculate the square root of an integer as follows:

Int I;
Double sqrtofi = SQRT (I );

Undoubtedly, C ++ allows implicit type conversion from int to double. Therefore, in SQRT calls, I is quietly converted to double type, and its return value is double. (For more information about implicit type conversion, see clause 5.) In general, catch clauses do not perform this conversion when they match an exception type. See the following code:

Void F (INT value)
{
Try {
If (somefunction ()){// If somefunction () returns
Throw value;// True, throwing an integer value
...
}
}
Catch (double D ){// Only handle exceptions of the Double Type
...
}

...

}

The Int exception thrown in the try block is not caught by the catch clause that handles the double exception. This clause can only capture exceptions with the true positive being of the double type. No type conversion is performed. Therefore, if you want to catch an int exception, you must use a catch clause with an int or an int & parameter.

However, when exception matching is performed in the catch clause, two types can be converted. The first type is the conversion between the inherited class and the base class. A catch clause used to capture the base class can also handle exceptions of the derived class type. For example, the diagnostic section (diagnostics portion) in the exception class hierarchy defined in the Standard C ++ Library (STL) (see article 49 of Objective C ++ ).

Catch clauses that capture runtime_errors exceptions can capture range_error and overflow_error exceptions. Catch clauses that receive root exception exceptions can capture exceptions of any of their derived classes.

The exception type conversion between the derived class and the base class (inheritance_based) can be applied to values, references, and pointers:

Catch (runtime_error )...// Can catch errors of Type
Catch (runtime_error &)...// Runtime_error
Catch (const runtime_error &)...// Range_error or
// Overflow_error

Catch (runtime_error *)...// Can catch errors of Type
Catch (const runtime_error *)...// Runtime_error *
                   // Range_error * or
// Overflow_error *

The second is to allow the conversion from a typed pointer to an untyped pointer, so the catch clause with the const void * pointer can catch any type of pointer type exception:

Catch (const void *)...// Catch any pointer type exception

The last difference between passing parameters and passing exceptions is that the matching order of catch clauses always depends on the order in which they appear in the program. Therefore, an exception in a derived class may be caught by a catch clause that handles the exception in its base class. Even if there are catch clauses that can handle the exception in the derived class at the same time, they correspond to the same try block. For example:

Try {
...
}
Catch (logic_error & Ex ){// This catch block will capture
...// All logic_error
}// Exception, including its derived class

Catch (invalid_argument & Ex ){// This block will never be executed
...// Because all
}// Invalid_argument
// All exceptions are
// Catch clause capture.

Contrary to the above behavior, when you call a virtual function, the called function is located in the class closest to the dynamic type of the object called by the function. You can say that virtual functions adopt the optimal method, while Exception Handling adopts the first method. If a catch clause that handles exceptions in a derived class is located before the catch clause that handles exceptions in the base class, the compiler will issue a warning. (Because such code is generally invalid in C ++ .) But you 'd better prevent it in advance: do not put the catch clause that handles exceptions of the base class before the catch clause that handles exceptions of the derived class. As in the above example, we should write the following code:

Try {
...
}
Catch (invalid_argument & Ex ){// Process invalid_argument
...// Exception
}
Catch (logic_error & Ex ){// Process all other
...// Logic_errors exception
}

To sum up, there are three main differences between passing an object to a function or an object to call a virtual function and throwing an object as an exception. First, the exception object is always copied during transmission. When it is captured by passing the value, the exception object is copied twice. Objects that are passed to functions as parameters do not need to be copied. Second, when an object is thrown as an exception, the former type conversion is less than the latter type when it is passed as a parameter (the former has only two conversion forms ). Finally, the catch clause performs exception type matching in the order they appear in the source code. The first catch with successful type matching will be used for execution. When an object calls a virtual function, the selected function is located in the class that best matches the object type, even if the class is not at the beginning of the source code.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.