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

📄 [17] exceptions and error handling, c++ faq lite.htm

📁 c++faq。里面有很多关于c++的问题的解答。
💻 HTM
📖 第 1 页 / 共 2 页
字号:
src="[17] Exceptions and error handling, C++ FAQ Lite.files/new.gif"></H3></DIV><SMALL><EM>[Recently 
created (on 7/00). <A 
href="http://www.sunistudio.com/cppfaq/exceptions.html#[17.5]">Click here to go 
to the next FAQ in the "chain" of recent 
changes<!--rawtext:[17.5]:rawtext--></A>.]</EM></SMALL> 
<P>往log文件中写一个消息。或打电话给Tilda舅妈。但不要抛出异常! 
<P>以下是为什么(扣好你的安全带): 
<P>C++的规则是你绝对不可以在另一个异常的被称为“栈展开(stack 
unwinding)”的过程中时,从析构函数抛出异常。举例来说,如果某人写了<TT>throw&nbsp;Foo()</TT>,栈会被展开,以至<TT>throw&nbsp;Foo()</TT>和 
<TT>}&nbsp;catch&nbsp;(Foo&nbsp;e)&nbsp;{</TT> 之间的所有的栈页面被弹出。这被称为<I>栈展开(statck 
unwinding)</I>
<P>在栈展开时,栈页面中的所有的局部对象会被析构。如果那些析构函数之一抛出异常(假定它抛出一个<TT>Bar</TT>对象),C++运行时系统会处于无法决断的境遇:应该忽略<TT>Bar</TT>并且在<TT>}&nbsp;catch&nbsp;(Foo&nbsp;e)&nbsp;{</TT> 
结束?应该忽略<TT>Foo</TT>并且寻找 <TT>}&nbsp;catch&nbsp;(Bar&nbsp;e)&nbsp;{</TT><TT> 
</TT>?没有好的答案——每个选择都会丢失信息。
<P>因此C++语言担保,当处于这一点时,会调用<TT>terminate()</TT>来杀死进程。突然死亡。
<P>防止这种情况的简单方法是<I>不要从析构函数中抛出异常</I>。但如果你真的要聪明一点,你可以说<I><U>当处理另一个异常的过程中时</U>,不要从析构函数抛出异常</I>。但在第二种情况中,你处于困难的境地:析构函数本身既需要代码处理抛出异常,还需要处理一些“其他东西”,调用者没有当析构函数检测到错误时会发生什么的担保(可能抛出异常,也可能做一些“其他事情”)。因此完整的解决方案非常难写。因此索性就做一些“其他事情”。也就是,<I>不要从析构函数中抛出异常</I>。
<P>当然,由于总有一些该规则无效的境况,这些话不应该被“引证”。但至少99%的情况下,这是一个好规则。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/exceptions.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/exceptions.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/freestore-mgmt.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/const-correctness.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[17.4]></A>
<DIV class=FaqTitle>
<H3>[17.4] 如果构造函数会抛出异常,我该怎样处理资源?</H3></DIV>
<P>对象中的每个数据成员应该清理自己。</P>
<P>如果构造函数抛出异常,对象的析构函数将不会运行。如果你的对象需要撤销一些已经做了的动作(如分配了内存,打开了一个文件,或者锁定了某个信号量),这些需要被撤销的动作必须被对象内部的一个数据成员记住。</P>
<P>例如,应该将分配的内存赋给对象的一个“智能指针”成员对象<TT>Fred</TT>,而不是分配内存给未被初始化的<TT>Fred*</TT> 
数据成员。这样当该智能指针消亡时,智能指针的析构函数将会删除<TT>Fred</TT>对象。标准类<TT>auto_ptr</TT>就是这种“智能指针”类的一个例子。你也可以<A 
href="http://www.sunistudio.com/cppfaq/freestore-mgmt.html#[16.21]">写你自己的引用计数智能指针</A>。你也可以<A 
href="http://www.sunistudio.com/cppfaq/operator-overloading.html#[13.3]">用智能指针来指向磁盘记录或者其它机器上的对象</A>。</P>
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/exceptions.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/exceptions.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/freestore-mgmt.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/const-correctness.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[17.5]></A>
<DIV class=FaqTitle>
<H3>[17.5] 当别人抛出异常时,我如何改变字符数组的字符串长度来防止内存泄漏? <IMG alt=UPDATED! 
src="[17] Exceptions and error handling, C++ FAQ Lite.files/updated.gif"></H3></DIV><SMALL><EM>[Recently 
rewrote the last half (on 7/00). <A 
href="http://www.sunistudio.com/cppfaq/const-correctness.html#[18.1]">Click here 
to go to the next FAQ in the "chain" of recent changes<!--rawtext:[18.1]:rawtext--></A>.]</EM></SMALL> 
<P>如果你要做的确实需要字符串,那么不要使用<TT>char</TT>数组,因为<A 
href="http://www.sunistudio.com/cppfaq/containers-and-templates.html#[31.1]">数组会带来麻烦</A>。应该用一些类似字符串类的对象来代替。 

<P>例如,假设你要得到一个字符串的拷贝,随意修改这个拷贝,然后在修改过的拷贝的字符串末尾添加其它的字符串。字符数组方法将是这样: 
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;void&nbsp;userCode(const&nbsp;char*&nbsp;s1,&nbsp;const&nbsp;char*&nbsp;s2)<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;制作s1的拷贝:</EM><TT><BR>&nbsp;&nbsp;&nbsp;char*&nbsp;copy&nbsp;=&nbsp;new&nbsp;char[strlen(s1)&nbsp;+&nbsp;1];<BR>&nbsp;&nbsp;&nbsp;strcpy(copy,&nbsp;s1);<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;现在我们有了一个指向分配了的自由存储的内存的指针,</EM><TT><BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;w我们需要用一个<TT>try</TT>块来防止内存泄漏:</EM><TT><BR>&nbsp;&nbsp;&nbsp;try&nbsp;{<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...&nbsp;n现在我们随意乱动这份拷贝...</EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;将s2 
添加到被修改过的 copy 
末尾:</EM><TT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...&nbsp;[在此处重分配 
copy]&nbsp;...</EM><TT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char*&nbsp;copy2&nbsp;=&nbsp;new&nbsp;char[strlen(copy)&nbsp;+&nbsp;strlen(s2)&nbsp;+&nbsp;1];<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(copy2,&nbsp;copy);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(copy2&nbsp;+&nbsp;strlen(copy),&nbsp;s2);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete[]&nbsp;copy;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;copy&nbsp;=&nbsp;copy2;<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...&nbsp;最后我们再次随意乱动拷贝...</EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(...)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete[]&nbsp;copy;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;得到一个异常时,防止内存泄漏</EM><TT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;重新抛出当前的异常<BR></EM><TT>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;delete[]&nbsp;copy;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;没有得到异常时,防止内存泄漏</EM><TT><BR>&nbsp;} 
</TT></DIV>
<P>象这样使用<TT>char*</TT>s是单调的并且容易发生错误。为什么不使用一个字符串类的对象呢?你的编译器也许提供了一个字符串类,而且它可能比你自己写的<TT>char*</TT>s更快,当然也更简单、更安全。例如,如果你使用了<A 
href="http://www.sunistudio.com/cppfaq/big-picture.html#[6.12]">标准化委员会</A>的字符串类<TT>std::string</TT>,你的代码看上去就会象这样: 

<P>
<DIV 
class=CodeBlock><TT>&nbsp;#include&nbsp;&lt;string&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;让编译器找到 
<TT>std::string</TT> 
类</EM><TT><BR>&nbsp;<BR>&nbsp;void&nbsp;userCode(const&nbsp;std::string&amp;&nbsp;s1,&nbsp;const&nbsp;std::string&amp;&nbsp;s2)<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;std::string&nbsp;copy&nbsp;=&nbsp;s1;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;制作s1的拷贝</EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...&nbsp;现在我们随意乱动这份拷贝...</EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;copy&nbsp;+=&nbsp;s2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;A将 
s2 
添加到被修改过的拷贝末尾</EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...&nbsp;最后我们再次随意乱动拷贝...</EM><TT><BR>&nbsp;} 
</TT></DIV>
<P>函数体中总共只有两行代码,而前一个例子中有12行代码。节省来自内存管理,但也有一些是来自于我们不必先式的调用<TT>str<EM>xxx</EM>()</TT>例程。这里有一些重点: 

<UL>
  <LI>由于<TT>std::string</TT>自动处理了内存管理,当增长字符串时,我们不需要先式地写任何分配内存的代码。 
  <LI>由于<TT>std::string</TT>自动处理了内存管理,在结束时不需要 <TT>delete[]</TT> 任何东西。 
  <LI>由于<TT>std::string</TT>自动处理了内存管理,在第二个例子中不需要 <TT>try</TT> 块,即使某人会在某处抛出异常。 
  </LI></UL>
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/exceptions.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/exceptions.html#bottom">Bottom</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/freestore-mgmt.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/const-correctness.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=bottom></A><A href="mailto:cline@parashift.com"><IMG height=26 
alt=E-Mail src="[17] Exceptions and error handling, C++ FAQ Lite.files/mbox.gif" 
width=89>&nbsp;E-mail the author</A><BR>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/index.html"><EM>C++ FAQ Lite</EM></A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/index.html#table-of-contents">Table&nbsp;of&nbsp;contents</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/subject-index.html">Subject&nbsp;index</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.1]">About&nbsp;the&nbsp;author</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/copy-permissions.html#[1.2]">&copy;</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/on-line-availability.html#[2.2]">Download&nbsp;your&nbsp;own&nbsp;copy</A>&nbsp;]<BR><SMALL>Revised 
Apr 8, 2001</SMALL> </P></BODY></HTML>

⌨️ 快捷键说明

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