📄 acis_tutorials_(exception_handling).htm
字号:
<ul><li class="toclevel-3"><a href="#A_C.2B.2B_example_3"><span class="tocnumber">4.3.1</span> <span class="toctext">A C++ example</span></a></li></ul></li></ul></li><li class="toclevel-1"><a href="#Some_Programming_Suggestions"><span class="tocnumber">5</span> <span class="toctext">Some Programming Suggestions</span></a></li></ul></li></ul></li></ul></td></tr></table><script type="text/javascript"> if (window.showTocToggle) { var tocShowText = "show"; var tocHideText = "hide"; showTocToggle(); } </script><p>Applications should be designed with exception handling in mind. In the event of an exception an application needs to be able to clean up allocated memory, repair data structures, and possibly try alternative solutions. ACIS provides two sets of macros to facilitate exception handling: the <i>EXCEPTION_***</i> set of macros and the <i>API_BEGIN / API_END</i> family of macros.</p><a name="The_EXCEPTION_.2A.2A.2A_macros"></a><h2> <span class="mw-headline"> The EXCEPTION_*** macros </span></h2><p>The EXCEPTION_*** set of macros have been designed to appear similar to the C++ try/catch paradigm. (The implementation of these macros is platform-specific and may or may not use try/catch.) These macros provide a foundation for writing exception-safe code. They are defined in <i>errorsys.hxx</i>. </p><p>The basic structure of an ACIS EXCEPTION block is shown below.</p><pre class="source-cpp"><span class="kw7">EXCEPTION_BEGIN</span> <span class="co1">// Declare variables that will be used during clean up.</span><span class="kw7">EXCEPTION_TRY</span> <span class="co1">// Perform geometric modeling operations.</span><span class="kw7">EXCEPTION_CATCH</span><span class="br0">(</span><span class="kw2">FALSE</span><span class="br0">)</span> <span class="co1">// Handle potential exceptions.</span><span class="kw7">EXCEPTION_END</span></pre><p>The EXCEPTION_*** macros contain { and } so you do not need to add these. The above example appears to define three blocks of code between the four macros. Actually, there are just two blocks of code. The outer block is defined between EXCEPTION_BEGIN and EXCEPTION_END. The inner block is defined between EXCEPTION_TRY and EXCEPTION_CATCH. Therefore, variables that are declared between EXCEPTION_BEGIN and EXCEPTION_TRY are in scope between EXCEPTION_CATCH and EXCEPTION_END. Alternatively, variables that are declared within the EXCEPTION_TRY / EXCEPTION_CATCH block are out of scope after the EXCEPTION_CATCH statement. In addition, variables that aredeclared anywhere in the EXCEPTION block will be out of scope after the EXCEPTION_END; therefore, any variables that must be visible after the EXCEPTION block should be declared before the EXCEPTION block. </p><p>A more specific example appears below.</p><pre class="source-cpp"><span class="kw7">EXCEPTION_BEGIN</span> <span class="kw5">SPAvector</span> * <span class="kw4">volatile</span> vec_array = <span class="kw2">NULL</span>;<span class="kw7">EXCEPTION_TRY</span> . . . <span class="me1">vec_array</span> = <span class="kw6">ACIS_NEW</span> <span class="kw5">SPAvector</span><span class="br0">[</span>NUM_VECS<span class="br0">]</span>; . . .<span class="kw7">EXCEPTION_CATCH</span><span class="br0">(</span><span class="kw2">FALSE</span><span class="br0">)</span> <span class="co1">// Process only if an exception occurs.</span> <span class="kw6">ACIS_DELETE</span> <span class="br0">[</span> <span class="br0">]</span> vec_array;<span class="kw7">EXCEPTION_END</span></pre><p>In the above example vec_array is declared in the section after the EXCEPTION_BEGIN macro, memory for it is allocated in the section between the EXCEPTION_TRY and EXCEPTION_CATCH macros, and in the event of an exception the memory is de-allocated in the section after the EXCEPTION_CATCH macro. </p><p>Why should all variables that are used in the clean up section be volatile? This is done so that they will not be created as register variables, so they will not be unexpectedly reset during exception handling. It is a common (and hard to find!) mistake not to declare all such variables as volatile.</p><p>What if you wanted a fail-safe means to <i>always</i> clean up vec_array? The EXCEPTION_CATCH macro takes an argument that specifies whether the block should always be executed or executed only in the event of an exception. If this argument is FALSE, as in the previous example, then the block is executed only in the event of an exception. If this argument is TRUE, then the block is always executed. This is demonstrated below.</p><pre class="source-cpp"><span class="kw7">EXCEPTION_BEGIN</span> <span class="kw5">SPAvector</span> * <span class="kw4">volatile</span> vec_array = <span class="kw2">NULL</span>;<span class="kw7">EXCEPTION_TRY</span> . . . <span class="me1">vec_array</span> = <span class="kw6">ACIS_NEW</span> <span class="kw5">SPAvector</span><span class="br0">[</span>NUM_VECS<span class="br0">]</span>; . . .<span class="kw7">EXCEPTION_CATCH</span><span class="br0">(</span><span class="kw2">TRUE</span><span class="br0">)</span> <span class="co1">// Always perform clean up.</span> <span class="kw6">ACIS_DELETE</span> <span class="br0">[</span> <span class="br0">]</span> vec_array;<span class="kw7">EXCEPTION_END</span></pre><p>A logical question you might ask at this point is, "What should I do if some clean up is always required and some is required only in the event of an exception?" In this case one can exaimine the variable <i>error_no</i> to determine if an exception occurred. If the value of <i>error_no</i> is non-zero, an exception has occurred. This is demonstrated below.</p><pre class="source-cpp"><span class="kw7">EXCEPTION_BEGIN</span> <span class="kw5">SPAvector</span> * <span class="kw4">volatile</span> vec_array1 = <span class="kw2">NULL</span>; <span class="kw5">SPAvector</span> * <span class="kw4">volatile</span> vec_array2 = <span class="kw2">NULL</span>;<span class="kw7">EXCEPTION_TRY</span> . . . <span class="me1">vec_array1</span> = <span class="kw6">ACIS_NEW</span> <span class="kw5">SPAvector</span><span class="br0">[</span>NUM_VEC1<span class="br0">]</span>; . . . <span class="me1">vec_array2</span> = <span class="kw6">ACIS_NEW</span> <span class="kw5">SPAvector</span><span class="br0">[</span>NUM_VEC2<span class="br0">]</span>; . . .<span class="kw7">EXCEPTION_CATCH</span><span class="br0">(</span><span class="kw2">TRUE</span><span class="br0">)</span> <span class="co1">// Always perform clean up.</span> <span class="kw6">ACIS_DELETE</span> <span class="br0">[</span> <span class="br0">]</span> vec_array1; <span class="kw1">if</span> <span class="br0">(</span>error_no != <span class="nu0">0</span><span class="br0">)</span> <span class="br0">{</span> <span class="co1">// Process only if an exception occurs.</span> <span class="kw1">if</span> <span class="br0">(</span>vec_array2 != <span class="kw2">NULL</span><span class="br0">)</span> <span class="kw6">ACIS_DELETE</span> <span class="br0">[</span> <span class="br0">]</span> vec_array2; <span class="br0">}</span><span class="kw7">EXCEPTION_END</span></pre><p>The ACIS EXCEPTION macros are designed to be nested, but the only place exceptions can occur is during the EXCEPTION_TRY / EXCEPTION_CATCH block. In other words, you should design you code so that exceptions will not occur before the EXCEPTION_TRY macro or after the EXCEPTION_CATCH macro. The EXCEPTION_END macro automatically resignals the error to next higher level EXCEPTION block. To prevent automatically passing control to the EXCEPTION_CATCH of the next higher level EXCEPTION block, you can set the value of <i>resignal_no</i> to 0. By default it is set to the value of <i>error_no</i>. Alternatively, one can use the EXCEPTION_END_NO_RESIGNAL macro. This is demonstrated in the example below in which <i>foo1( )</i> calls <i>foo2( )</i>. If an exception occurs in <i>foo2( )</i> it is propagated to <i>foo1( )</i>, but <i>foo1( )</i> does not propagate the exception to its calling function.</p><pre class="source-cpp"><span class="kw4">void</span> foo1<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw7">EXCEPTION_BEGIN</span> <span class="kw5">SPAvector</span> * <span class="kw4">volatile</span> vec_array1 = <span class="kw2">NULL</span>; <span class="kw7">EXCEPTION_TRY</span> . . . <span class="me1">vec_array1</span> = <span class="kw6">ACIS_NEW</span> <span class="kw5">SPAvector</span><span class="br0">[</span>NUM_VEC1<span class="br0">]</span>; . . . <span class="me1">foo2</span><span class="br0">(</span><span class="br0">)</span>; . . . <span class="kw7">EXCEPTION_CATCH</span><span class="br0">(</span><span class="kw2">FALSE</span><span class="br0">)</span> <span class="co1">// Process only if an exception occurs.</span> <span class="kw6">ACIS_DELETE</span> <span class="br0">[</span> <span class="br0">]</span> vec_array1; <span class="kw7">EXCEPTION_END_NO_RESIGNAL</span><span class="br0">}</span><span class="kw4">void</span> foo2<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw7">EXCEPTION_BEGIN</span> <span class="kw5">SPAvector</span> * <span class="kw4">volatile</span> vec_array2 = <span class="kw2">NULL</span>; <span class="kw7">EXCEPTION_TRY</span> . . . <span class="me1">vec_array2</span> = <span class="kw6">ACIS_NEW</span> <span class="kw5">SPAvector</span><span class="br0">[</span>NUM_VEC2<span class="br0">]</span>; . . . <span class="kw7">EXCEPTION_CATCH</span><span class="br0">(</span><span class="kw2">FALSE</span><span class="br0">)</span> <span class="co1">// Process only if an exception occurs.</span> <span class="kw6">ACIS_DELETE</span> <span class="br0">[</span> <span class="br0">]</span> vec_array2; <span class="kw7">EXCEPTION_END</span><span class="br0">}</span></pre><p>Notice that in the event of an exception all of the memory allocations that occurred in <i>foo2( )</i> are cleaned up in <i>foo2( )</i> and all of the memory allocations that occurred in <i>foo1( )</i> are cleaned up in <i>foo1( )</i>. </p><p>There are two EXCEPTION_*** macros that we have not mentioned but may be of interest to you: EXCEPTION_CATCH_FALSE and EXCEPTION_CATCH_TRUE. The behavior of these macros is identical to EXCEPTION_CATCH(FALSE) and EXCEPTION_CATCH(TRUE). These macros were introduced because EXCEPTION_CATCH(FALSE) and EXCEPTION_CATCH(TRUE) cause compiler warnings on some platforms. Of course, EXCEPTION_CATCH_FALSE and EXCEPTION_CATCH_TRUE may cause compiler warnings on other platforms. The choice as to which to use is up to you. </p><p>The complete set of EXCEPTION_*** macros is summarized below.</p><table class="wikitable"><tr><th> Macro</th><th> Description</th></tr><tr><td> EXCEPTION_BEGIN</td><td> start of the variable declaration section</td></tr><tr><td> EXCEPTION_TRY</td><td> start of the algorithmic section</td></tr><tr><td> EXCEPTION_CATCH(AlwaysClean)</td><td> start of the cleanup section<p>processing depends on the value of AlwaysClean</p></td></tr><tr><td> EXCEPTION_CATCH_FALSE</td><td> Logically the same as EXCEPTION_CATCH(FALSE)</td></tr><tr><td> EXCEPTION_CATCH_TRUE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -