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