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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 1 页 / 共 4 页
字号:
  under cfront, and under any other compiler in general.</p>
<h3> <a name="Heading7">The Challenges of Implementation of Exception Handling</a></h3>
<p>The difficulties in implementing exception handling arise from several factors. 
  First, the implementation must ensure that the proper handler for a specific 
  exception is found. </p>
<p>Secondly, exception objects can be polymorphic; in that case, the implementation 
  also considers handlers of base classes when it cannot locate a matching handler 
  for a derived object.. This requirement implies a sort of runtime type checking 
  to recover the dynamic type of the exception object. Yet C++ did not have any 
  runtime type checking facilities whatsoever before exception handling was developed; 
  these facilities had to be created from scratch for that purpose. </p>
<p>As an additional complication, the implementation must invoke the destructors 
  of all local objects that were constructed on the path from a <tt>try</tt> block 
  to a <tt>throw</tt> expression before control passes to the appropriate handler. 
  This process is called <i>stack</i> <i>unwinding</i> (the stack unwinding process 
  is discussed in further detail later in this chapter). Because early C++ compilers 
  translated the C++ source file into pure C and only then compiled the code into 
  machine code, the implementers of exception handling had to implement runtime 
  type identification and stack unwinding in C. Fortunately, these obstacles have 
  all been overcome.</p>
<h2> <a name="Heading8">Applying Exception Handling</a></h2>
<p>Exception handling is a flexible and sophisticated tool. It overcomes the drawbacks 
  of C's traditional error handling methods and it can be used to handle a variety 
  of runtime errors. Still, exception handling, like other language features, 
  can easily be misused. To use this feature effectively, it is important to understand 
  how the underlying runtime machinery works and what the associated performance 
  penalties are. The following sections delve into exception handling internals 
  and demonstrate how to use this tool to create robust, bulletproof applications.</p>
<blockquote>
  <hr>
  <strong>CAUTION: </strong> Some of the code samples in the following sections 
  use new exception handling features such as function try blocks and exception 
  specifications. Several compilers do not support these features yet; therefore, 
  it is recommended that you read the technical documentation of your compiler 
  to check whether it fully supports exception handling. 
  <hr>
</blockquote>
<h3> <a name="Heading9">Exception Handling Constituents</a></h3>
<p>Exception handling is a mechanism for transferring control from a point in 
  a program where an exception occurs to a matching handler. Exceptions are variables 
  of built-in data types or class objects. The exception handling mechanism consists 
  of four components: a <tt>try</tt><i> block</i>, a sequence of one or more <i>handlers</i> 
  associated with a <tt>try</tt> block, a <tt>throw</tt><i> expression</i>, and 
  the exception itself. The <tt>try</tt> block contains code that might throw 
  an exception. For example</p>
<pre>
<tt>try </tt>
<tt>{</tt>
<tt> int * p = new int[1000000]; //may throw std::bad_alloc</tt>
<tt>}</tt>
</pre>
<p>A <tt>try</tt> block is followed by a sequence of one or more <tt>catch</tt> 
  statements, or handlers, each of which handles a different type of exception. 
  For example</p>
<pre>
<tt>try</tt>
<tt>{</tt>
<tt> int * p = new int[1000000]; //may throw std::bad_alloc</tt>
<tt> //...</tt>
<tt>}</tt>
<tt>catch(std::bad_alloc&amp; ) </tt>
<tt>{</tt>
<tt>}</tt>
<tt>catch (std::bad_cast&amp;)</tt>
<tt>{</tt>
<tt>}</tt>
</pre>
<p>A handler is invoked only by a <tt>throw</tt> expression that is executed in 
  the handler's <tt>try</tt> block or in functions that are called from the handler's 
  <tt>try</tt> block. A <tt>throw</tt> expression consists of the keyword <tt>throw</tt> 
  and an <cite>assignment expression</cite>. For example</p>
<pre>
<tt>try</tt>
<tt>{</tt>
<tt> throw 5; // 5 is assigned to n in the following catch statement</tt>
<tt>}</tt>
<tt>catch(int n) </tt>
<tt>{</tt>
<tt>}</tt>
</pre>
<p>A <tt>throw</tt><i> </i>expression is similar to a <tt>return</tt> statement. 
  An <i>empty throw</i> is a <tt>throw</tt> statement without an operand. For 
  example</p>
<pre>
<tt>throw; </tt>
</pre>
<p>An empty throw inside a handler indicates a <i>rethrow</i>, which is discussed 
  momentarily. Otherwise, if no exception is presently being handled, executing 
  an empty throw calls <tt>terminate()</tt>. </p>
<h3> <a name="Heading10">Stack Unwinding</a></h3>
<p>When an exception is thrown, the runtime mechanism first searches for an appropriate 
  handler in the current scope. If such a handler does not exist, </p>
<p>the current scope is exited and the block that is higher in the calling chain 
  is entered into scope. This process is iterative: It continues until an appropriate 
  handler has been found. An exception is considered to be handled upon its entry 
  to a handler. At this point, the stack has been unwound and all the local objects 
  that were constructed on the path from a <tt>try</tt> block to a <tt>throw</tt> 
  expression have been destroyed. In the absence of an appropriate handler, the 
  program terminates. Note, however, that C++ ensures proper destruction of local 
  objects only when the thrown exception is handled. Whether an uncaught exception 
  causes the destruction of local objects during stack unwinding is implementation-dependent. 
  To ensure that destructors of local objects are invoked in the case of an uncaught 
  exception, you can add a <tt>catch</tt> <tt>all</tt> statement in <tt>main()</tt>. 
  For example</p>
<pre>
<tt>int main()</tt>
<tt>{</tt>
<tt>  try</tt>
<tt>  {</tt>
<tt>    //...</tt>
<tt>  }</tt>
<tt>  catch(std::exception&amp; stdexc)   // handle expected exceptions</tt>
<tt>  {</tt>
<tt>    //...</tt>
<tt>  }</tt>
<tt>  catch(...)   // ensure proper cleanup in the case of an uncaught exception</tt>
<tt>  {</tt>
<tt>  }</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<p>The stack unwinding process is very similar to a sequence of <tt>return</tt> 
  statements, each returning the same object to its caller. </p>
<h3> <a name="Heading11">Passing Exception Objects to a Handler</a></h3>
<p>An exception can be passed by value or by reference to its handler. The memory 
  for the exception that is being thrown is allocated in an unspecified way (but 
  it is not allocated on the free store). Some implementations use a dedicated 
  exception stack, on which exception objects are created. When an exception is 
  passed by reference, the handler receives a reference to the exception object 
  that is constructed on the exception stack. Passing an exception by reference 
  ensures its polymorphic behavior. Exceptions that are passed by value are constructed 
  on the stack frame of the caller. For example </p>
<pre>
<tt>#include  &lt;cstdio&gt;</tt>
<tt>class ExBase {/*...*/};</tt>
<tt>class FileEx: public ExBase {/*...*/};</tt>
<tt>void Write(FILE *pf)</tt>
<tt>{</tt>
<tt>  if (pf == NULL) throw FileEx();</tt>
<tt>  //... process pf normally</tt>
<tt>}</tt>
<tt>int main ()</tt>
<tt>{</tt>
<tt>  try</tt>
<tt>  {</tt>
<tt>    Write(NULL); //will cause a FileEx exception to be thrown</tt>
<tt>  }</tt>
<tt>  catch(ExBase&amp; exception) //catch ExBase or any object derived from it</tt>
<tt>  {</tt>
<tt>  //diagnostics and remedies   }</tt>
<tt>}</tt>
</pre>
<p>Repeatedly copying objects that are passed by value is costly because the exception 
  object can be constructed and destroyed several times before a matching handler 
  has been found. However, it occurs only when an exception is thrown, which only 
  happens in abnormal and -- hopefully -- rare situations. Under these circumstances, 
  performance considerations are secondary (exception handling performance is 
  discussed at the end of this chapter) to maintaining an application's integrity.</p>
<h3> <a name="Heading12">Exception Type Match</a></h3>
<p>The type of an exception determines which handler can catch it. The matching 
  rules for exceptions are more restrictive than are the matching rules for function 
  overloading. Consider the following example:</p>
<pre>
<tt>try</tt>
<tt>{</tt>
<tt>  throw int();</tt>
<tt>}</tt>
<tt>catch (unsigned int) //will not catch the exception from the previous try-block</tt>
<tt>{		 </tt>
<tt>}</tt>
</pre>
<p>The thrown exception is of type <tt>int</tt>, whereas the handler expects an 
  <tt>unsigned int</tt>. The exception handling mechanism does not consider these 
  to be matching types; as a result, the thrown exception is not caught. The matching 
  rules for exceptions allow only a limited set of conversions: For an exception 
  <tt>E</tt> and a handler taking <tt>T</tt> or <tt>T&amp;</tt>, the match is 
  valid under one of the following conditions: </p>
<ul>
  <li>
    <p> <tt>T</tt> and <tt>E</tt> are of the same type (<tt>const</tt> and <tt>volatile</tt> 
      specifiers are ignored)</p>
  </li>
  <p></p>
  <li>
    <p> <tt>T</tt> is an unambiguous public base class of . </p>
  </li>
</ul>
<p></p>
<p>If <tt>E</tt> and <tt>T</tt> are pointers, the match is valid if <tt>E</tt> 
  and <tt>T</tt> are of the same type or if <tt>E</tt> points to an object that 
  is publicly and unambiguously derived from the class that is pointed to by <tt>T</tt>. 
  In addition, a handler of type <tt>array of T</tt> or <tt>function returning 
  T</tt> is transformed into <tt>pointer to T</tt> or <tt>pointer to function 
  returning T</tt>, respectively.</p>
<h3> <a name="Heading13">Exceptions as Objects</a></h3>
<p></p>
<p>As you have probably noticed, the traditional convention of returning an integer 
  as an error flag is problematic and unsatisfactory in OOP. The C++ exception 
  handling mechanism offers more flexibility, safety, and robustness. An exception 
  can be a fundamental type such as <tt>int</tt> or a <tt>char *</tt>. It can 
  be a full-fledged object as well, with data members and member functions. Such 
  an object can provide the exception handler with more options for recovery. 
  A clever exception object, for example, can have a member function that returns 
  a detailed verbal description of the error, instead of letting the handler to 
  look it up in a table or a file. It can have member functions that enable the 
  program to recover from the runtime error after the error has been handled properly. 
  Consider a logger class that appends new records to an existing log file: If 
  it fails to open the log file, it throws an exception. When it is caught by 
  the matching handler, the exception object can have a member function, which 
  creates a dialog box. The operator can choose recovery measures from the dialog 
  box, including creation of a new log file, redirecting the logger to an alternative 
  file, or simply allowing the system to run without a logger.</p>
<h3> <a name="Heading14">Exception Specification</a></h3>
<p>A function that might throw an exception can warn its users by specifying a 
  list of the exceptions that it can throw. Exception specifications are particularly 
  useful when users of a function can view its prototype but cannot access its 
  source file. Following is an example of specifying an exception:</p>
<pre>
<tt>class Zerodivide{/*..*/};</tt>
<tt>int divide (int, int) throw(Zerodivide);   // function may throw an exception</tt>
<tt>                                           // of type Zerodivide, but no other</tt>
</pre>
<p>If your function never throws any exceptions, it can be declared as follows:</p>
<pre>
<tt>bool equals (int, int) throw(); //no exception is thrown from this function</tt>
</pre>
<p>Note that a function that is declared without an exception specification such 
  as</p>
<pre>
<tt>bool equals (int, int);</tt>
</pre>
<h4> guarantees nothing about its exceptions: It might throw any exception, or 
  it might throw no exceptions. Exception Specifications Are Enforced At Runtime</h4>
<p>An exception specification may not be checked at compile time, </p>
<p>but rather at runtime. When a function attempts to throw an exception that 
  it is not allowed to throw according to its exception specification, the exception 
  handling mechanism detects the violation and invokes the standard function <tt>unexpected()</tt>. 
  The default behavior of <tt>unexpected()</tt> is to call <tt>terminate()</tt>, 
  which terminates the program. A violation of an exception specification is most 
  likely a bug, and should not occur -- this is why the default behavior is program 
  termination. The default behavior can be altered, nonetheless, by using the 
  function <tt>set_unexpected().</tt></p>
<p>Because exception specifications are enforced only at runtime, the compiler 
  might deliberately ignore code that seemingly violates exception specifications. 
  Consider the following:</p>
<pre>

⌨️ 快捷键说明

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