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

📄 index.html

📁 C程序员手册(英文)
💻 HTML
📖 第 1 页 / 共 4 页
字号:
<tt>int f();    // no exception specification, f can throw any type of exception</tt>
<tt>void g(int j) throw()    // g promises not to throw any exception at all</tt>
<tt>{</tt>
<tt>  int result = f(); // if f throws an exception, g will violate its guarantee</tt>
<tt>                    //not to throw an exception. still, this code is legal</tt>
<tt>}</tt>
</pre>
<p>In this example, the function <tt>g()</tt>, which is not allowed to throw any 
  exception, invokes the function <tt>f()</tt>. <tt>f()</tt>, however, is free 
  to throw any exception because it has no exception specification. If <tt>f()</tt> 
  throws an exception, it propagates through <tt>g()</tt>, thereby violating <tt>g()</tt>'s 
  guarantee not to throw any exception.It might seem surprising that exception 
  specifications are enforced only at runtime because at least some of the violations 
  can be caught at compile time and flagged as errors. This is not the case, however. 
  There are several compelling reasons for the runtime checking policy.. In the 
  preceding example, <tt>f()</tt> can be a legacy C function. It is impossible 
  to enforce every C function to have an exception specification. Forcing the 
  programmer to write unnecessary <tt>try</tt> and <tt>catch(...)</tt> blocks 
  in <tt>g()</tt> "just in case" is impractical as well -- what if the programmer 
  knows that <tt>f()</tt> doesn't throw any exception at all and the code is therefore 
  safe? By enforcing exception specifications at runtime, C++ applies the "trust 
  the programmer" policy instead of forcing an unnecessary burden on both the 
  programmer and the implementation.</p>
<h4> Concordance of Exception Specification</h4>
<p>C++ requires exception specification concordance in derived classes. This means 
  that an overriding virtual function in a derived class has to have an exception 
  specification that is at least as restrictive as the exception specification 
  of the overridden function in the base class. For example</p>
<pre>
<tt>// various exception classes</tt>
<tt>class BaseEx{};</tt>
<tt>class DerivedEx: public BaseEx{};</tt>
<tt>class OtherEx {};</tt>
<tt>class A</tt>
<tt>{</tt>
<tt>public:</tt>
<tt>  virtual void f() throw (BaseEx);</tt>
<tt>  virtual void g() throw (BaseEx);</tt>
<tt>  virtual void h() throw (DerivedEx);</tt>
<tt>  virtual void i() throw (DerivedEx);</tt>
<tt>  virtual void j() throw(BaseEx);</tt>
<tt>};</tt>
<tt>class D: public A</tt>
<tt>{</tt>
<tt>public: </tt>
<tt>  void f() throw (DerivedEx); //OK, DerivedEx is derived from BaseEx</tt>
<tt>class D: public A</tt>
<tt>{</tt>
<tt>public: </tt>
<tt>  void f() throw (DerivedEx); //OK, DerivedEx is derived from BaseEx</tt>
<tt>  void g() throw (OtherEx);  //error; exception specification is </tt>
<tt>                             //incompatible with A's</tt>
<tt>  void h() throw (DerivedEx); //OK, identical to the exception </tt>
<tt>                              //specification in base</tt>
<tt>  void i() throw (BaseEx); //error, BaseEx is not a DerivedEx nor is it</tt>
<tt>                           //derived from DerivedEx</tt>
<tt>  void j()  throw (BaseEx,OtherEx); //error, less restrictive than the</tt>
<tt>                                    //specification of A::j</tt>
<tt>};</tt>
<tt>};</tt>
</pre>
<p>The same concordance restrictions apply to pointers to functions. A pointer 
  to a function that has an exception specification can be assigned only to a 
  function that has an identical or a more restrictive exception specification. 
  This implies that a pointer to function that has no exception specification 
  cannot be assigned to a function that has one. Note, however, that an exception 
  specification is not considered part of the function type. Therefore, you cannot 
  declare two distinct functions that differ only in their exception specification. 
  For example</p>
<pre>
<tt>void f(int) throw (Y);</tt>
<tt>void f(int) throw (Z); //error; redefinition of 'void f(int)'</tt>
</pre>
<p>For the same reason, declaring a <tt>typedef</tt> that contains an exception 
  specification is also an error:</p>
<pre>
<tt>typedef void (*PF) (int) throw(Exception); // error</tt>
</pre>
<h2> <a name="Heading15">Exceptions During Object's Construction and Destruction</a></h2>
<p>Constructors and destructors are invoked automatically; in addition, they cannot 
  return values to indicate a runtime error. Seemingly, the most plausible way 
  of reporting runtime errors during object construction and destruction is by 
  throwing an exception. However, there are additional factors that you have to 
  consider before throwing an exception in these cases. You should be particularly 
  cautious about throwing an exception from a destructor.</p>
<h3> <a name="Heading16">Throwing Exceptions From A Destructor is Dangerous</a></h3>
<p>Throwing an exception from a destructor is not recommended. The problem is 
  that a destructor might be invoked due to another exception as part of the stack 
  unwinding. If a destructor that was invoked due to another exception also throws 
  an exception of its own, the exception handling mechanism invokes <tt>terminate()</tt>. 
  If you really have to throw an exception from a destructor, it is advisable 
  to check first whether another uncaught exception is currently being processed. 
</p>
<h4> Checking for an Uncaught Exception</h4>
<p>A thrown exception is considered caught when its corresponding handler has 
  been entered (or, if such a handler cannot be found, when the function <tt>unexpected()</tt> 
  has been invoked). In order to check whether a thrown exception is currently 
  being processed, you can use the standard function <tt>uncaught_exception()</tt> 
  (which is defined in the standard header &lt;stdexcept&gt;). For example</p>
<pre>
<tt>class FileException{};</tt>
<tt>File::~File() throw (FileException)</tt>
<tt>{</tt>
<tt>   if ( close(file_handle) != success) // failed to close current file?</tt>
<tt>  {</tt>
<tt>    if (uncaught_exception()  == true ) // is there any uncaught exception </tt>
<tt>                                        //being processed currently?</tt>
<tt>       return;  // if so, do not throw an exception</tt>
<tt>    throw FileException(); // otherwise, it is safe to throw an exception</tt>
<tt>                           // to signal an error</tt>
<tt>  }</tt>
<tt>  return; // success</tt>
<tt>}</tt>
</pre>
<p>Still, a better design choice is to handle exceptions within a destructor rather 
  than let them propagate into the program. For example</p>
<pre>
<tt>void cleanup() throw (int);</tt>
<tt>class C </tt>
<tt>{</tt>
<tt>public:</tt>
<tt>  ~C();</tt>
<tt>};</tt>
<tt>C::~C() </tt>
<tt>{</tt>
<tt>  try </tt>
<tt>  {</tt>
<tt>    cleanup();</tt>
<tt>  }</tt>
<tt>  catch(int) </tt>
<tt>  {</tt>
<tt>    //handle the exception within the destructor</tt>
<tt>  }</tt>
<tt>}</tt>
</pre>
<p>If an exception is thrown by <tt>cleanup()</tt>, it is handled inside the destructor. 
  Otherwise, the thrown exception will propagate outside the destructor, and if 
  the destructor has been invoked while unwinding the stack due to another exception, 
  <tt>terminate()</tt> will be called.</p>
<h2> <a name="Heading17">Global Objects: Construction and Destruction</a></h2>
<p>Conceptually, the construction of global objects takes place before program 
  outset. Therefore, any exception that is thrown from a constructor of a global 
  object can never be caught. This is also true for a global object's destructor 
  -- the destruction of a global object executes after a program's termination. 
  Hence, an exception that is thrown from a global object's destructor cannot 
  be handled either. </p>
<h2> <a name="Heading18">Advanced Exception Handling Techniques</a></h2>
<p>The simple <tt>try</tt>-<tt>throw</tt>-<tt>catch</tt> model can be extended 
  even further to handle more complicated runtime errors. This section discusses 
  some of the more advanced uses of exception handling, including exception hierarchies, 
  rethrowing exceptions, function <tt>try</tt> blocks and the <tt>auto_ptr</tt> 
  class. </p>
<h3> <a name="Heading19">Standard Exceptions</a></h3>
<p>C++ defines a hierarchy of standard exceptions that are thrown at runtime when 
  abnormal conditions arise. The standard exception classes are derived from <tt>std::exception</tt> 
  (defined in the &lt;stdexcept&gt; header). This hierarchy enables the application 
  to catch these exceptions in a single <tt>catch</tt> statement:</p>
<pre>
<tt>catch (std::exception&amp; exc)</tt>
<tt>{</tt>
<tt>  // handle exception of type std::exception as well as </tt>
<tt>  //any exception derived from it</tt>
<tt>}</tt>
</pre>
<p>The standard exceptions that are thrown by built-in operators of the language 
  are</p>
<pre>
<tt>std::bad_alloc     //by operator new</tt>
<tt>std::bad_cast     //by operator dynamic_cast &lt; &gt;</tt>
<tt>std::bad_typeid   //by operator typeid</tt>
<tt>std::bad_exception   //thrown when an exception specification of </tt>
</pre>
<p> //a function is violatedAll standard exceptions have provided the member function 
  <tt>what()</tt>, which returns a <tt>const char *</tt> with an implementation-dependent 
  verbal description of the exception. Note, however, that the standard library 
  has an additional set of exceptions that are thrown by its components.</p>
<h3> <a name="Heading20">Exception Handlers Hierarchy</a></h3>
<p>Exceptions are caught in a bottom-down hierarchy: Specific (most derived classes) 
  exceptions are handled first, followed by groups of exceptions (base classes), 
  and, finally, a <tt>catch all</tt> handler. For example</p>
<pre>
<tt>#include &lt;stdexcept&gt;  </tt>
<tt>#include &lt;iostream&gt;</tt>
<tt>using namespace std;</tt>
<tt>int main()</tt>
<tt>{</tt>
<tt>  try</tt>
<tt>  {</tt>
<tt>      char * buff = new char[100000000];</tt>
<tt>      //...use buff</tt>
<tt>  }</tt>
<tt>  catch(bad_alloc&amp; alloc_failure)   // bad_alloc is </tt>
<tt>                                         //derived from exception</tt>
<tt>  {</tt>
<tt>    cout&lt;&lt;"memory allocation failure";</tt>
<tt>    //... handle exception thrown by operator new</tt>
<tt>  }</tt>
<tt>  catch(exception&amp; std_ex) </tt>
<tt>  {</tt>
<tt>    cout&lt;&lt; std_ex.what() &lt;&lt;endl; </tt>
<tt>  }</tt>
<tt>  catch(...)  // exceptions that are not handled elsewhere are caught here</tt>
<tt>  {</tt>
<tt>    cout&lt;&lt;"unrecognized exception"&lt;&lt;endl;</tt>
<tt>  }</tt>
<tt>  return 0;</tt>
<tt>}</tt>
</pre>
<p>Handlers of the most derived objects must appear before the handlers of base 
  classes. This is because handlers are tried in order of appearance. It is therefore 
  possible to write handlers that are never executed, for example, by placing 
  a handler for a derived class after a handler for a corresponding base class. 
  For example</p>
<pre>
<tt>catch(std::exception&amp; std_ex) //bad_alloc exception is always handled here   </tt>
<tt>{</tt>
<tt>  //...handle the exception </tt>
<tt>}</tt>
<tt>catch(std::bad_alloc&amp; alloc_failure)   //unreachable </tt>
<tt>{</tt>
<tt>  cout&lt;&lt;"memory allocation failure";</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading21">Rethrowing an Exception</a></h3>
<p>An exception is thrown to indicate an abnormal state. The first handle to catch 
  the exception can try to fix the problem. If it fails to do so, or if it only 
  manages to perform a partial recovery, it can still rethrow the exception, thereby 
  letting a higher <tt>try</tt> block handle it. For that purpose, <tt>try</tt> 
  blocks can be nested in a hierarchical order, enabling a rethrown exception 
  from a lower <tt>catch</tt> statement to be caught again. A rethrow is indicated 
  by a <tt>throw</tt> statement without an operand. For example</p>
<pre>
<tt>#include &lt;iostream&gt;</tt>
<tt>#include &lt;string&gt;</tt>
<tt>using namespace std;</tt>
<tt>enum {SUCCESS, FAILURE};</tt>
<tt>class File</tt>
<tt>{</tt>
<tt>  public: File (const char *) {}</tt>
<tt>  public: bool IsValid() const {return false; }</tt>
<tt>  public: int OpenNew() const {return FAILURE; }</tt>
<tt>};</tt>
<tt>class Exception {/*..*/}; //general base class for exceptions</tt>
<tt>class FileException: public Exception</tt>
<tt>{</tt>
<tt>  public: FileException(const char *p) : s(p) {}</tt>

⌨️ 快捷键说明

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