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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 1 页 / 共 4 页
字号:
<tt>  public: const char * Error() const { return s.c_str(); }</tt>
<tt>  private: string s;</tt>
<tt>};</tt>
<tt>void func(File&amp; );</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  try //outer try</tt>
<tt>  {</tt>
<tt>    File f ("db.dat");</tt>
<tt>    func;   // 1</tt>
<tt>  }</tt>
<tt>catch(...) // 7</tt>
<tt>  //this handler will catch the re-thrown exception; </tt>
<tt>  //note: the same exception type is required</tt>
<tt>  {</tt>
<tt>    cout&lt;&lt;"re-thrown exception caught";</tt>
<tt>  }</tt>
<tt>  return 0;</tt>
<tt>}</tt>
<tt>void func(File &amp; f)</tt>
<tt>{</tt>
<tt>  try //inner try</tt>
<tt>  {</tt>
<tt>      if (f.IsValid() == false )</tt>
<tt>      throw FileException("db.dat");  // 2</tt>
<tt>  }</tt>
<tt>  catch(FileException &amp;fe) // 3</tt>
<tt>//first chance to cope with the exception</tt>
<tt>  {</tt>
<tt>    cout&lt;&lt;"invalid file specification" &lt;&lt;fe.Error()&lt;&lt;endl;</tt>
<tt>    if (f.OpenNew() != SUCCESS) (5)</tt>
<tt>     //re-throw the original exception and let a higher handler deal with it</tt>
<tt>    throw; // 6</tt>
<tt>  }</tt>
<tt>}</tt>
</pre>
<p>In the preceding example, the function <tt>func()</tt> is called from the <tt>try</tt> 
  block inside <tt>main()</tt> (1). The second <tt>try</tt> block inside <tt>func()</tt> 
  throws an exception of type <tt>FileException</tt> (2). This exception is caught 
  by the <tt>catch</tt> block inside <tt>func()</tt> (3). The <tt>catch</tt> block 
  attempts to remedy the situation by opening a new file. This attempt fails (5), 
  and the <tt>FileException</tt> is rethrown (6). Finally, the rethrown exception 
  is caught -- this time, by the <tt>catch(...)</tt> block inside <tt>main()</tt> 
  (7).</p>
<h3> <a name="Heading22">Function try Blocks</a></h3>
<p>A <i>function</i> <tt>try</tt><i> block</i> is a function whose body consists 
  of a <tt>try</tt> block and its associated handlers. A function <tt>try</tt> 
  block enables a handler to catch an exception </p>
<p>that is thrown during the execution of the <i>initializer expressions</i> in 
  the constructor's member initialization list or during the execution of the 
  constructor's body. Note, however, that unlike handlers of ordinary exceptions, 
  the handler of a function <tt>try</tt> block merely catches the exception -- 
  it cannot continue the object's construction normally. This is because the partially 
  constructed object is destroyed as a result of the stack unwinding. In addition, 
  the handler of a function <tt>try</tt> block cannot execute a <tt>return</tt> 
  statement (eventually, the handler must exit by a <tt>throw</tt>). What is the 
  use of a function <tt>try</tt> block then? The handler enables you to throw 
  a different exception than the one that it just caught, thereby preventing a 
  violation of the exception specification. For example</p>
<pre>
<tt>class X{}; </tt>
<tt>C::C(const std::string&amp; s) throw (X) //  allowed to throw X only </tt>
<tt>try</tt>
<tt>: str(s) // str's constructor might throw a bad_alloc exception, </tt>
<tt>         // might violate C's exception specification</tt>
<tt>{</tt>
<tt>  // constructor function body</tt>
<tt>}</tt>
<tt>catch (...) //handle any exception thrown from ctor initializer or ctor body</tt>
<tt>{</tt>
<tt>  //... </tt>
<tt>  throw X(); //replace bad_alloc exception with an exception of type X</tt>
<tt>}</tt>
</pre>
<p>In this example, a <tt>string</tt> object is first constructed as a member 
  of class <tt>C</tt>. <tt>string</tt> might throw a <tt>bad_alloc</tt> exception 
  during its construction. The function try block catches the <tt>bad_alloc</tt> 
  exception and throws instead an exception of type <tt>X</tt>, which satisfies 
  the exception specification of <tt>C</tt>'s constructor.</p>
<h3> <a name="Heading23">Use auto_ptr&lt;&gt; to Avoid Memory Leaks</a></h3>
<p>The Standard Library supplies the class template <tt>auto_ptr&lt;&gt;</tt> 
  (discussed in Chapter 10, "STL and Generic Programming"), which automatically 
  deallocates memory that is allocated on the free store in much the same manner 
  as local objects are reclaimed in case of exiting their scope. When an <tt>auto_ptr&lt;&gt;</tt> 
  is instantiated, it can be initialized with a pointer to an object that is allocated 
  on the free store. When the current scope is exited, the destructor of the <tt>auto_ptr&lt;&gt;</tt> 
  object automatically deletes the object that is bound to it. By using <tt>auto_ptr&lt;&gt;</tt>, 
  you can avoid memory leakage in the case of an exception. Furthermore, <tt>auto_ptr&lt;&gt;</tt> 
  can simplify programming by sparing the bother of explicitly deleting objects 
  that were allocated on the free store. <tt>auto_ptr&lt;&gt;</tt> is defined 
  in the standard <tt>&lt;memory&gt;</tt> header file. </p>
<p>For example</p>
<pre>
<tt>#include &lt;memory&gt;</tt>
<tt>#include &lt;iostream&gt;</tt>
<tt>using namespace std;</tt>
<tt>class Date{ public: const char * DateString(); };</tt>
<tt>void DisplayDate()</tt>
<tt>{</tt>
<tt>        //create a local object of type auto_ptr&lt;Date&gt;</tt>
<tt>  auto_ptr&lt;Date&gt; pd (new Date); //now pd is owned by the template object</tt>
<tt>  cout&lt;&lt; pd-&gt; DateString();</tt>
<tt>  //pd is automatically deleted by the destructor of auto_ptr; </tt>
<tt>}</tt>
</pre>
<p>In the preceding example, the <tt>auto_ptr&lt;&gt;</tt> instance, <tt>pd</tt>, 
  can be used like an ordinary pointer to <tt>Date</tt>. The overloaded operators 
  <tt>*</tt>, <tt>-&gt;</tt>, and <tt>&amp;</tt> of <tt>auto_ptr&lt;&gt;</tt> 
  provide the pointer-like syntax. <tt>pd</tt>'s<tt> bound object </tt> is automatically 
  destroyed when <tt>DisplayDate()</tt> exits.</p>
<h2> <a name="Heading24"> Exception Handling Performance Overhead</a></h2>
<p>By nature, exception handling relies heavily on runtime type checking. When 
  an exception is thrown, the implementation has to determine whether the exception 
  was thrown from a <tt>try</tt> block (an exception can be thrown from a program 
  section that is not enclosed within a <tt>try</tt> block -- by operator <tt>new</tt>, 
  for example). If indeed the exception was thrown from a <tt>try</tt> block, 
  the implementation compares the type of the exception and attempts to find a 
  matching handler in the current scope. If a match is found, control is transferred 
  to the handler's body. This is the optimistic scenario. What if the implementation 
  cannot find a matching handler for the exception, though, or what if the exception 
  was not thrown from a <tt>try</tt> block? In such a case, the current function 
  is unwound from the stack and the next active function in the stack is entered. 
  The same process is reiterated until a matching handler has been found (at that 
  point, all the automatic objects that were created on the path from a <tt>try</tt> 
  block to a <tt>throw</tt> expression have been destroyed). When no matching 
  handler can be found in the program, <tt>terminate()</tt> is invoked and the 
  program terminates.</p>
<h3> <a name="Heading25">Additional Runtime Type Information</a></h3>
<p>The exception handling mechanism has to store additional data about the type 
  of every exception object and every <tt>catch</tt> statement in order to perform 
  the runtime matching between an exception and its matching handler. Because 
  an exception can be of any type, and because it can be polymorphic as well, 
  its dynamic type must be queried at runtime, using <i>runtime type information</i> 
  (<i>RTTI</i>). RTTI, imposes an additional overhead in terms of both execution 
  speed and program size (see Chapter 7, "Runtime Type Information"). Yet RTTI 
  alone is not enough. The implementation also requires runtime <i>code</i> information, 
  that is, information about the structure of each function. This information 
  is needed to determine whether an exception was thrown from a <tt>try</tt> block. 
  This information is generated by the compiler in the following way: The compiler 
  divides each function body into three parts: one that is outside a <tt>try</tt> 
  block with no active objects, a second part that is also outside a <tt>try</tt> 
  block but that has active objects that have to be destroyed during stack unwinding, 
  and a third part that is within a <tt>try</tt> block.</p>
<h3> <a name="Heading26">Toggling Exception Handling Support</a></h3>
<p>The technicalities of exception handling implementation vary among compilers 
  and platforms. In all of them, however, exception handling imposes additional 
  overhead even when no exception is ever thrown. The overhead lies in both execution 
  speed and program size. Some compilers enable you to toggle exception handling 
  support. When it is turned off, the additional data structures, lookup tables, 
  and auxiliary code are not generated. However, turning off exception handling 
  is rarely an option. Even if you do not use exceptions directly, you are probably 
  using them implicitly: Operator <tt>new</tt>, for example, might throw a <tt>std::bad_alloc</tt> 
  exception when it fails -- and so do other built-in operators; STL containers 
  might throw their own exceptions, and so might other functions of the Standard 
  Library. Code libraries that are supplied by third party vendors might use exceptions 
  as well. Therefore, you can safely turn off exception handling support only 
  when you are porting pure C code into a C++ compiler. As long as pure C code 
  is used, the additional exception handling overhead is unnecessary and can be 
  avoided.</p>
<h2> <a name="Heading27">Misuses of Exception Handling</a></h2>
<p>Exception handling is not confined to errors. Some programmers might use it 
  simply as an alternative control structure to <tt>for</tt> loops or <tt>while</tt> 
  and <tt>do</tt> blocks. For example, a simple application that prompts the user 
  to enter data until a certain condition has been fulfilled can be (rather naively) 
  implemented as follows:</p>
<pre>
<tt>#include &lt;iostream&gt;</tt>
<tt>using namespace std;</tt>
<tt>class Exit{}; //used as exception object</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt> int num;</tt>
<tt> cout&lt;&lt; "enter a number; 99 to exit" &lt;&lt;endl;</tt>
<tt> try</tt>
<tt> {</tt>
<tt>   while (true) //infinitely</tt>
<tt>   {</tt>
<tt>     cin&gt;&gt;num;</tt>
<tt>     if (num == 99)</tt>
<tt>         throw Exit(); //exit the loop</tt>
<tt>     cout&lt;&lt; "you entered: " &lt;&lt; num &lt;&lt; "enter another number " &lt;&lt;endl;</tt>
<tt>   }</tt>
<tt> }</tt>
<tt> catch (Exit&amp; )</tt>
<tt> {</tt>
<tt>   cout&lt;&lt; "game over" &lt;&lt;endl;</tt>
<tt> }</tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
<p>In the preceding example, the programmer locates an infinite loop within a 
  try block. The <tt>throw</tt> statement breaks the loop and transfers control 
  to the following <tt>catch</tt> statement. This style of programming is not 
  recommended, however. It is very inefficient due to the excess overhead of exception 
  handling. Furthermore, it is rather verbose and might have been much simpler 
  and shorter had it been written with a <tt>break</tt> statement. In demo apps 
  such as this one, the difference is mostly a stylistic one. In large-scale applications, 
  the use of exception handling as an alternative control structure imposes a 
  significant performance overhead.</p>
<p>Simple runtime errors that can be handled safely and effectively without the 
  heavy machinery of exception handling need to also be treated by traditional 
  methods. For example, a password entry dialog box should not throw an exception 
  if the user mistyped his or her password. It is much simpler to redisplay the 
  password entry dialog again with an appropriate error message. On the other 
  hand, if the user enters wrong passwords dozens of times in a row, this can 
  indicate a malicious break-in attempt. In this case, an exception should be 
  thrown. The appropriate handler can page the system administrator and security 
  officer. </p>
<h2> <a name="Heading28">Conclusions</a></h2>
<p>The exception handling mechanism of C++ overcomes the problems associated with 
  the traditional methods. It frees the programmer from writing tedious code that 
  checks the success status of every function call. Exception handling also eliminates 
  human mistakes. Another important advantage of exception handling is the automatic 
  unwinding of the stack, which ensures that local active objects are properly 
  destroyed and their resources are released.</p>
<p>Implementing an exception handling mechanism was not a trivial task. The need 
  to query the dynamic type of exception led to the introduction of RTTI into 
  C++. The additional overhead of exception handling derives from the RTTI data 
  structures, the "scaffolding" code that is generated by the compiler, and other 
  implementation-dependent factors. Exceptions can be grouped into categories; 
  the standard exception classes are a good example of this. In recent years, 
  a few loopholes in the exception handling mechanism have been fixed. The first 
  was the addition of exception specifications to functions' prototypes. The second 
  was the introduction of a function <tt>try</tt> block, which enables the program 
  to handle an exception that is thrown during the execution of the initializer 
  expressions in the constructor's member initialization list or during the execution 
  of the constructor's body.</p>
<p>Exception handling is a very powerful and flexible tool for handling runtime 
  errors effectively. However, use it judiciously.</p>
<CENTER>
<P>
<HR>
  <A HREF="/publishers/que/series/professional/0789720221/index.htm"><img src="/publishers/que/series/professional/0789720221/button/contents.gif" WIDTH="128"
HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A> <BR>
<BR>
<BR>
<p></P>

<P>&#169; <A HREF="/publishers/que/series/professional/0789720221/copy.htm">Copyright 1999</A>, Macmillan Computer Publishing. All
rights reserved.</p>
</CENTER>


</BODY>

</HTML>

⌨️ 快捷键说明

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