📄 chap7_5.htm
字号:
<p>对于第一种技术,要求程序员记住各种错误代码,并且加入大量的检查情况。由于大多数错误是很少会发生,这样处理的结果是代码冗余性很大,效率不高。</p>
<p>第二种技术不但使程序可读性降低,更严重的是,使得函数里的对象不能释放、删除。比如:</p>
<p>void SomeOperation()</p>
<p>{</p>
<p>CMyClass obj1;</p>
<p>if(error)goto errHandler;</p>
<p>...</p>
<p>}</p>
<p>...</p>
<p>errHandler:</p>
<p>//handler error</p>
<p>在上面的程序片断中,由于goto跳转,无法调用obj的析构函数在退出</p>
<p>SomeOperation()函数时释放其所占的内存,造成内存泄漏。</p>
<p>而且,以上两种错误处理方法都无法考虑到不可预见的错误。C++引入异常处理这一重要概念很好的解决了上述问题。异常处理在处理异常事件时会自动调用已经超出范围的局部对象的析构函数,这样就可以防止内存泄漏。
</p>
<p>下面是OnSaveDocument()函数中的异常处理代码:</font><font FACE="Times New Roman" SIZE="3"></p>
<p>CFile file;</p>
<p>CFileException fe;</p>
<p>if (!file.Open(lpszPathName, CFile::modeCreate |</p>
<p>CFile::modeReadWrite | CFile::shareExclusive, &fe))</p>
<p>{</p>
<p>ReportSaveLoadException(lpszPathName, &fe,</p>
<p>TRUE, AFX_IDP_INVALID_FILENAME);</p>
<p>return FALSE;</p>
<p>}</font><font SIZE="3"></p>
<p></font><font FACE="Times New Roman" SIZE="3">// replace calls to Serialize with SaveDIB
function</p>
<p>BOOL bSuccess = FALSE;</p>
<p>TRY</p>
<p>{</p>
<p>BeginWaitCursor();</p>
<p>bSuccess = ::SaveDIB(m_hDIB, file);</p>
<p>file.Close();</p>
<p>}</p>
<p>CATCH (CException, eSave)</p>
<p>{</p>
<p>file.Abort(); // will not throw an exception</p>
<p>EndWaitCursor();</p>
<p>ReportSaveLoadException(lpszPathName, eSave,</p>
<p>TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);</p>
<p>return FALSE;</p>
<p>}</p>
<p>END_CATCH</p>
<p ALIGN="JUSTIFY"></font><font SIZE="3">异常处理由一个</font><font FACE="Times New Roman" SIZE="3">TRY-CATCH-END_CATCH</font><font SIZE="3">结构组成。</font><font FACE="Times New Roman" SIZE="3">TRY{ }</font><font SIZE="3">语句块中包含可能发生错误的代码,可以理解为“试运行”这一语句块。</font><font FACE="Times New Roman" SIZE="3">CATCH{} END_CATCH</font><font SIZE="3">子块包含了错误处理代码。如果发生错误,就转入</font><font FACE="Times New Roman" SIZE="3">CATCH{} END_CATCH</font><font SIZE="3">子块执行。该子块可以根据</font><font FACE="Times New Roman" SIZE="3">CATCH</font><font SIZE="3">中的参数分析产生错误的原因,报告错误或做出相应处理。</font><font FACE="Times New Roman" SIZE="3"></p>
<p>CATCH()</font><font SIZE="3">包含两个参数,第一个参数是异常类。</font><font FACE="Times New Roman" SIZE="3">MFC</font><font SIZE="3">的异常有下列几种:</font><font FACE="Times New Roman" SIZE="3"></p>
<p></font> </p>
<div align="center"><center><table BORDER="1" CELLSPACING="2" BORDERCOLOR="#7F7F7F" CELLPADDING="1" WIDTH="473">
<tr>
<td WIDTH="33%"><font FACE="Times New Roman" SIZE="3"><p ALIGN="CENTER">MFC</font><font SIZE="3">异常类</font></td>
<td WIDTH="67%"><font SIZE="3"><p ALIGN="CENTER">处理的异常</font></td>
</tr>
<tr>
<td WIDTH="33%"><font FACE="Times New Roman" SIZE="3">CMemoryException</font></td>
<td WIDTH="67%"><font SIZE="3">内存异常</font></td>
</tr>
<tr>
<td WIDTH="33%"><font FACE="Times New Roman" SIZE="3">CNotSupportedException</font></td>
<td WIDTH="67%"><font SIZE="3">设备不支持</font></td>
</tr>
<tr>
<td WIDTH="33%"><font FACE="Times New Roman" SIZE="3">CArchiveException</font></td>
<td WIDTH="67%"><font SIZE="3">档案</font><font FACE="Times New Roman" SIZE="3">(archive)</font><font SIZE="3">异常</font></td>
</tr>
<tr>
<td WIDTH="33%"><font FACE="Times New Roman" SIZE="3">CFileException</font></td>
<td WIDTH="67%"><font SIZE="3">文件异常</font></td>
</tr>
<tr>
<td WIDTH="33%"><font FACE="Times New Roman" SIZE="3">OsErrorException</font></td>
<td WIDTH="67%"><font SIZE="3">把</font><font FACE="Times New Roman" SIZE="3">DOS</font><font SIZE="3">错误转换为异常</font></td>
</tr>
<tr>
<td WIDTH="33%"><font FACE="Times New Roman" SIZE="3">ErrnoToException</font></td>
<td WIDTH="67%"><font SIZE="3">把错误号转换为异常</font></td>
</tr>
<tr>
<td WIDTH="33%"><font FACE="Times New Roman" SIZE="3">CResourceException</font></td>
<td WIDTH="67%"><font SIZE="3">资源异常</font></td>
</tr>
<tr>
<td WIDTH="33%"><font FACE="Times New Roman" SIZE="3">COleException</font></td>
<td WIDTH="67%"><font FACE="Times New Roman" SIZE="3">OLE</font><font SIZE="3">异常</font></td>
</tr>
</table>
</center></div><p><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">用户还可以从</font><font FACE="Times New Roman" SIZE="3">CException</font><font SIZE="3">类派生出自己的异常类,用以处理特定类型的错误。</font><font FACE="Times New Roman" SIZE="3"></p>
<p>CATCH</font><font SIZE="3">的第二个参数是产生的异常的名字。</font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">引起异常的原因存放在异常的数据成员</font><font FACE="Times New Roman" SIZE="3">m_cause</font><font SIZE="3">中。</font><font FACE="Times New Roman" SIZE="3">OnSaveDocument()</font><font SIZE="3">只是简单的处理文件保存错误,并没有指出引起错误的原因。我们可以对它进行一些修改,使它能够报告引起错误的原因。</font><font FACE="Times New Roman" SIZE="3"></p>
<p>... </p>
<p>TRY</p>
<p>{</p>
<p>...</p>
<p>}</p>
<p>CATCH(CFileException,e)</p>
<p>{</p>
<p>switch(e->m_cause)</p>
<p>{</p>
<p>case CFileException::accessDenied:</p>
<p>AfxMessageBox(</font><font SIZE="3">“</font><font FACE="Times New Roman" SIZE="3">Access
denied!</font><font SIZE="3">”</font><font FACE="Times New Roman" SIZE="3">); </p>
<p>break;</p>
<p>case CFileException::badPath: </p>
<p>AfxMessageBox(</font><font SIZE="3">“</font><font FACE="Times New Roman" SIZE="3">Invalid
path name</font><font SIZE="3">”</font><font FACE="Times New Roman" SIZE="3">); </p>
<p>break;</p>
<p>case CFileException::diskFull:</p>
<p>AfxMessageBox(</font><font SIZE="3">“</font><font FACE="Times New Roman" SIZE="3">Disk
is full</font><font SIZE="3">”</font><font FACE="Times New Roman" SIZE="3">);</p>
<p>break;</p>
<p>case CFileException::hardIO:</p>
<p>AfxMessageBox(</font><font SIZE="3">“</font><font FACE="Times New Roman" SIZE="3">Hardware
error</font><font SIZE="3">”</font><font FACE="Times New Roman" SIZE="3">);</p>
<p>break;</p>
<p>}</p>
<p>}</p>
<p>END_CATCH</p>
<p>...</p>
<p>}</p>
<p></font><font SIZE="3">用户也可以不必直接处理异常,而通过调用</font><font FACE="Times New Roman" SIZE="3">THROW_LAST()</font><font SIZE="3">,把异常交给上一级</font><font FACE="Times New Roman" SIZE="3">TRY-CATCH</font><font SIZE="3">结构来处理。其实,在</font><font FACE="Times New Roman" SIZE="3">DIBLOOK</font><font SIZE="3">中,就是这么做的,请看</font><font FACE="Times New Roman" SIZE="3">OnSaveDocument()</font><font SIZE="3">函数调用的</font><font FACE="Times New Roman" SIZE="3">SaveDIB</font><font SIZE="3">函数的片段:</font><font FACE="Times New Roman" SIZE="3"></p>
<p>BOOL WINAPI SaveDIB(HDIB hDib, CFile& file)</p>
<p>{</p>
<p>//...</p>
<p>TRY</p>
<p>{</p>
<p>//...</p>
<p>}</p>
<p>CATCH (CFileException, e)</p>
<p>{</p>
<p>//...</p>
<p>::GlobalUnlock((HGLOBAL) hDib);</p>
<p>THROW_LAST();</p>
<p>}</p>
<p>END_CATCH</p>
<p>//...</p>
<p>}</p>
<p></font><font SIZE="3">在</font><font FACE="Times New Roman" SIZE="3">SaveDIB</font><font SIZE="3">中,并没有直接处理异常,而是通过调用</font><font FACE="Times New Roman" SIZE="3">THROW_LAST()</font><font SIZE="3">,把异常交由调用它的上一级函数</font><font FACE="Times New Roman" SIZE="3">OnSaveDocument()</font><font SIZE="3">去处理。</font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">异常并不仅仅用于错误处理。比如,在文本编辑器的</font><font FACE="Times New Roman" SIZE="3">CEditorDoc::Serialize()</font><font SIZE="3">成员函数中,我们就利用读取文件引起的异常判断是否已经到了文件尾部。读者请回顾一下该函数。</font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">异常处理给程序的错误处理带来许多便利。但是,必需意识到异常处理并不是万能的。在加入异常处理后,程序员仍然有许多工作要做。更不可以滥用异常,因为异常会带来一些开销。应用程序应当尽可能排除可能出现的错误。</font><b></p>
<p> </p>
</b><div align="center"><center><table border="0" cellpadding="0" cellspacing="0" width="615">
<tr>
<td><a href="chap7_4.htm">上一页</a></td>
<td><p align="right"><a href="chap7_6.htm">下一页</a></td>
</tr>
</table>
</center></div><font SIZE="5"><hr noshade color="#3973DE" size="1">
<p align="center"></font><font size="2" color="#000000">本教程由<a href="http://vcdynasty.yeah.net">Visual C++王朝(Where programmers come together)</a>协助制作<br>
未经许可,请勿以任何形式复制</font></td>
<b>
</tr>
</table>
</center></div>
<p ALIGN="CENTER"></b><font SIZE="5"> </font><font FACE="Times New Roman" SIZE="5"></p>
</font><font FACE="Times New Roman" SIZE="3">
<p></font><b><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
</font></b>
<p><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p></font> </p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -