⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mi12.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 2 页
字号:
</PRE>
</UL><A NAME="67215"></A>
<UL><PRE>
catch (Widget&amp; w) ...               // catch exception by
                                    // reference
</PRE>
</UL><A NAME="67203"></A>
<UL><PRE>
catch (const Widget&amp; w) ...         // catch exception by
                                    // reference-to-const
</PRE>
</UL><P><A NAME="dingp17"></A><A NAME="67204"></A>
Right away we notice another difference between parameter passing and exception propagation. A thrown object (which, as explained <A NAME="p65"></A>above, is always a temporary) may be caught by simple reference; it need not be caught by reference-to-<CODE>const</CODE>. Passing a temporary object to a non-<CODE>const</CODE> reference parameter is not allowed for function calls (see <A HREF="./MI19_FR.HTM#41177" TARGET="_top">Item 19</A>), but it is for <NOBR>exceptions.<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>    <P><A NAME="dingp18"></A><A NAME="67347"></A>
Let us overlook this difference, however, and return to our examination of copying exception objects. We know that when we pass a function argument by value, we make a copy of the passed object (see <a href="../EC/EI22_FR.HTM#6133" TARGET="_top">Item E22</A>), and we store that copy in a function parameter. The same thing happens when we pass an exception by value. Thus, when we declare a <CODE>catch</CODE> clause like <NOBR>this,<SCRIPT>create_link(18);</SCRIPT>
</NOBR></P><A NAME="67364"></A>
<UL><PRE>
catch (Widget w) ...                // catch by value
</PRE>
</UL><A NAME="67362"></A>
<A NAME="dingp19"></A><P><A NAME="dingp19"></A>we expect to pay for the creation of <I>two</I> copies of the thrown object, one to create the temporary that all exceptions generate, the second to copy that temporary into <CODE>w</CODE>. Similarly, when we catch an exception by <NOBR>reference,<SCRIPT>create_link(19);</SCRIPT>
</NOBR></P>
<A NAME="67378"></A>
<UL><PRE>
catch (Widget&amp; w) ...               // catch by reference
<A NAME="67395"></A>
catch (const Widget&amp; w) ...         // also catch by reference
</PRE>
</UL><A NAME="67376"></A>
<P><A NAME="dingp20"></A>we still expect to pay for the creation of a copy of the exception: the copy that is the temporary. In contrast, when we pass function parameters by reference, no copying takes place. When throwing an exception, then, we expect to construct (and later destruct) one more copy of the thrown object than if we passed the same object to a <NOBR>function.<SCRIPT>create_link(20);</SCRIPT>
</NOBR></P><A NAME="67429"></A>
<P><A NAME="dingp21"></A>
We have not yet discussed throwing exceptions by pointer, but throw by pointer is equivalent to pass by pointer. Either way, a copy of the <I>pointer</I> is passed. About all you need to remember is not to throw a pointer to a local object, because that local object will be destroyed when the exception leaves the local object's scope. The <CODE>catch</CODE> clause would then be initialized with a pointer to an object that had already been destroyed. This is the behavior the mandatory copying rule is designed to <NOBR>avoid.<SCRIPT>create_link(21);</SCRIPT>
</NOBR></P><A NAME="67510"></A>
<P><A NAME="dingp22"></A>
The way in which objects are moved from call or <CODE>throw</CODE> sites to parameters or <CODE>catch</CODE> clauses is one way in which argument passing differs from exception propagation. A second difference lies in what constitutes a type match between caller or thrower and callee or catcher. Consider the <CODE>sqrt</CODE> function from the standard math <NOBR>library:<SCRIPT>create_link(22);</SCRIPT>
</NOBR></P>
<A NAME="67516"></A>
<UL><PRE>
double sqrt(double);                 // from &lt;cmath&gt; or &lt;math.h&gt;
</PRE>
</UL><A NAME="67523"></A>
<P><A NAME="dingp23"></A>
We can determine the square root of an integer like <NOBR>this:<SCRIPT>create_link(23);</SCRIPT>
</NOBR></P>
<A NAME="67524"></A>
<UL><PRE>int i;
<A NAME="67525"></A>
double sqrtOfi = sqrt(i);
</PRE>
</UL>

<A NAME="67526"></A>
<A NAME="p66"></A>
<P><A NAME="dingp24"></A>
There is nothing surprising here. The language allows implicit conversion from <CODE>int</CODE> to <CODE>double</CODE>, so in the call to <CODE>sqrt</CODE>, <CODE>i</CODE> is silently converted to a <CODE>double</CODE>, and the result of <CODE>sqrt</CODE> corresponds to that <CODE>double</CODE>. (See <A HREF="./MI5_FR.HTM#5970" TARGET="_top">Item 5</A> for a fuller discussion of implicit type conversions.) In general, such conversions are not applied when matching exceptions to <CODE>catch</CODE> clauses. In this <NOBR>code,<SCRIPT>create_link(24);</SCRIPT>
</NOBR></P>
<A NAME="67553"></A>
<UL><PRE>void f(int value)
{
  try {
    if (someFunction()) {      // if someFunction() returns
      throw value;             // true, throw an int
    ...
    }
  }
  catch (double d) {           // handle exceptions of
    ...                        // type double here
  }
<A NAME="67554"></A>
  ...
<A NAME="67555"></A>
}
</PRE>
</UL><A NAME="71555"></A>
<P><A NAME="dingp25"></A>the <CODE>int</CODE> exception thrown inside the <CODE>try</CODE> block will never be caught by the <CODE>catch</CODE> clause that takes a <CODE>double</CODE>. That clause catches only exceptions that are exactly of type <CODE>double</CODE>; no type conversions are applied. As a result, if the <CODE>int</CODE> exception is to be caught, it will have to be by some other (dynamically enclosing) <CODE>catch</CODE> clause taking an <CODE>int</CODE> or an <CODE>int&amp;</CODE> (possibly modified by <CODE>const</CODE> or <CODE>volatile</CODE>).<SCRIPT>create_link(25);</SCRIPT>
</P>
<A NAME="79570"></A>
<P><A NAME="dingp26"></A>
Two kinds of conversions <I>are</I> applied when matching exceptions to <CODE>catch</CODE> clauses. The first is inheritance-based conversions. A <CODE>catch</CODE> clause for base class exceptions is allowed to handle exceptions of derived class types, too. For example, consider the diagnostics portion of the hierarchy of exceptions defined by the standard C++ library (see <A HREF="../EC/EI49_FR.HTM#8392" TARGET="_top">Item E49</A>):<SCRIPT>create_link(26);</SCRIPT>
</P>

<SPAN ID="Image1of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_066A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_066A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_066A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_066A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_066A5.GIF" BORDER=0></SPAN>

<SPAN ID="Image1of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_066A5.GIF" BORDER=0></SPAN>

<A NAME="67576"></A>

<P><A NAME="p67"></A><A NAME="dingp27"></A>
A <CODE>catch</CODE> clause for <CODE>runtime_error</CODE>s can catch exceptions of type <CODE>range_error</CODE> and <CODE>overflow_error</CODE>, too, and a <CODE>catch</CODE> clause accepting an object of the root class <CODE>exception</CODE> can catch any kind of exception derived from this <NOBR>hierarchy.<SCRIPT>create_link(27);</SCRIPT>
</NOBR></P><A NAME="68229"></A>
<P><A NAME="dingp28"></A>
This inheritance-based exception-conversion rule applies to values, references, and pointers in the usual <NOBR>fashion:<SCRIPT>create_link(28);</SCRIPT>
</NOBR></P>
<A NAME="68056"></A>
<UL><PRE>
catch (runtime_error) ...               // can catch errors of type
catch (runtime_error&amp;) ...              // runtime_error,
catch (const runtime_error&amp;) ...        // range_error, or
                                        // overflow_error
</PRE>
</UL><A NAME="68074"></A>
<UL><PRE>
catch (runtime_error*) ...              // can catch errors of type
catch (const runtime_error*) ...        // runtime_error*,
                                        // range_error*, or
                                        // overflow_error*
</PRE>
</UL><A NAME="79593"></A>
<P><A NAME="dingp29"></A>
The second type of allowed conversion is from a typed to an untyped pointer, so a <CODE>catch</CODE> clause taking a <CODE>const</CODE> <CODE>void*</CODE> pointer will catch an exception of any pointer <NOBR>type:<SCRIPT>create_link(29);</SCRIPT>
</NOBR></P>
<A NAME="79603"></A>
<UL><PRE>
catch (const void*) ...                 // catches any exception
                                        // that's a pointer
</PRE>
</UL><A NAME="68072"></A>
<P><A NAME="dingp30"></A>
The final difference between passing a parameter and propagating an exception is that <CODE>catch</CODE> clauses are always tried <I>in the order of their appearance</I>. Hence, it is possible for an exception of a derived class type to be handled by a <CODE>catch</CODE> clause for one of its base class types &#151; even when a <CODE>catch</CODE> clause for the derived class is associated with the same <CODE>try</CODE> block! For <NOBR>example,<SCRIPT>create_link(30);</SCRIPT>
</NOBR></P>
<A NAME="68082"></A>
<UL><PRE>try {
  ...
}
catch (logic_error&amp; ex) {              // this block will catch
  ...                                  // <i>all</i> logic_error
}                                      // exceptions, even those
                                       // of derived types
<A NAME="68087"></A>
catch (invalid_argument&amp; ex) {         // this block can <i>never</i> be
  ...                                  // executed, because all
}                                      // invalid_argument
                                       // exceptions will be caught
                                       // by the clause above
</PRE>
</UL><A NAME="68094"></A>
<P><A NAME="dingp31"></A>
Contrast this behavior with what happens when you call a virtual function. When you call a virtual function, the function invoked is the one in the class <I>closest</I> to the dynamic type of the object invoking the function. You might say that virtual functions employ a "best fit" algorithm, while exception handling follows a "first fit" strategy. Compilers may warn you if a <CODE>catch</CODE> clause for a derived class comes after one for a base class (some issue an error, because such code used to be illegal <A NAME="p68"></A>in C++), but your best course of action is preemptive: never put a <CODE>catch</CODE> clause for a base class before a <CODE>catch</CODE> clause for a derived class. The code above, for example, should be reordered like <NOBR>this:<SCRIPT>create_link(31);</SCRIPT>
</NOBR></P>
<A NAME="68128"></A>
<UL><PRE>try {
  ...
}
catch (invalid_argument&amp; ex) {          // handle invalid_argument
  ...                                   // exceptions here
}
catch (logic_error&amp; ex) {               // handle all other
  ...                                   // logic_errors here
}
</PRE>
</UL><A NAME="68147"></A>
<P><A NAME="dingp32"></A>
There are thus three primary ways in which passing an object to a function or using that object to invoke a virtual function differs from throwing the object as an exception. First, exception objects are always copied; when caught by value, they are copied twice. Objects passed to function parameters need not be copied at all. Second, objects thrown as exceptions are subject to fewer forms of type conversion than are objects passed to functions. Finally, <CODE>catch</CODE> clauses are examined in the order in which they appear in the source code, and the first one that can succeed is selected for execution. When an object is used to invoke a virtual function, the function selected is the one that provides the <I>best</I> match for the type of the object, even if it's not the first one listed in the source <NOBR>code.<SCRIPT>create_link(32);</SCRIPT>
</NOBR></P>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI11_FR.HTM" TARGET="_top">Item 11: Prevent exceptions from leaving destructors</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MI13_FR.HTM" TARGET="_top">Item 13: Catch exceptions by reference</A></FONT></DIV>
</BODY>
</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -