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

📄 [11] destructors, c++ faq lite.htm

📁 c++faq。里面有很多关于c++的问题的解答。
💻 HTM
📖 第 1 页 / 共 2 页
字号:
class=CodeBlock><TT>&nbsp;void&nbsp;someCode()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;f;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...&nbsp;[这些代码在 
<TT>f 
</TT>打开的时候执行]&nbsp;...</EM><TT><BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;</TT><EM>//&nbsp;^—&nbsp;<TT>f</TT>&nbsp;的析构函数在此处会被自动调用!</EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...&nbsp;[</EM><EM>这些代码在 
<TT>f</TT> 关闭后执行</EM><EM>]&nbsp;...</EM><TT><BR>&nbsp;} </TT></DIV>
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[11.8]></A>
<DIV class=FaqTitle>
<H3>[11.8] 如果我无法将局部对象包裹于人为的块中,怎么办?</H3></DIV>
<P>大多数时候艘,你可以通过<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#[11.7]">将局部对象包裹于人为的<TT>{</TT>...<TT>}</TT>块中</A>,限制其生命期。但如果由于一些原因无法这样做,则增加一个模拟析构函数作用的成员函数。但<I>不要调用析构函数本身</I>!
<P>例如,<TT>File</TT>类的情况下,可以添加一个<TT>close()</TT>方法。典型的析构函数只是调用<TT>close()</TT>方法。注意<TT>close()</TT>方法需要标记 
<TT>File </TT>对象,以便后续的调用不会再次关闭一个已经关闭的文件。举例来说,可以将一个<TT>fileHandle_</TT>数据成员设置为 
-1,并且在开头检查<TT>fileHandle_</TT>是否已经等于-1:
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;class&nbsp;File&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;void&nbsp;close();<BR>&nbsp;&nbsp;&nbsp;~File();<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;int&nbsp;fileHandle_;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;<TT>当且仅当文件打开时 
fileHandle_&nbsp;&gt;=&nbsp;0</TT></EM><TT><BR>&nbsp;};<BR>&nbsp;<BR>&nbsp;File::~File()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;close();<BR>&nbsp;}<BR>&nbsp;<BR>&nbsp;void&nbsp;File::close()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(fileHandle_&nbsp;&gt;=&nbsp;0)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...&nbsp;[执行一些操作-系统调用来关闭文件]&nbsp;...</EM><TT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fileHandle_&nbsp;=&nbsp;-1;<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;} 
</TT></DIV>
<P>注意其他的 <TT>File</TT>方法可能也需要检查<TT>fileHandle_</TT>是否为 -1(也就是说,检查文件是否被关闭了)。
<P>还要注意任何没有实际打开文件的构造函数,都应该将<TT>fileHandle_</TT>设置为 -1。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[11.9]></A>
<DIV class=FaqTitle>
<H3>[11.9] 如果我是用<TT>new</TT>分配对象的,可以显式调用析构函数吗?</H3></DIV>
<P>可能不行。
<P>除非你使用<A href="http://www.sunistudio.com/cppfaq/dtors.html#[11.10]">定位放置 
<TT>new</TT></A>,否则应该 <TT>delete </TT>对象而不是显式调用析构函数。例如,假设通过一个典型的 <TT>new 
</TT>表达式分配一个对象:
<P> 
<DIV class=CodeBlock><TT>&nbsp;Fred*&nbsp;p&nbsp;=&nbsp;new&nbsp;Fred(); 
</TT></DIV>
<P>那么,当你<TT>delete</TT>它时,析构函数 <TT>Fred::~Fred() </TT>会被调用: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;delete&nbsp;p;&nbsp;&nbsp;</TT><EM>//&nbsp;自动调用&nbsp;<TT>p-&gt;~Fred()</TT></EM><TT> 
</TT></DIV>
<P>由于显式调用析构函数不会释放 <TT>Fred </TT>对象本身分配的内存,因此不要这样做。记住:<A 
href="http://www.sunistudio.com/cppfaq/freestore-mgmt.html#[16.8]"><TT>delete&nbsp;p</TT> 
做了两件事情</A>:调用析构函数,回收内存。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[11.10]></A>
<DIV class=FaqTitle>
<H3>[11.10] 什么是“定位放置<TT>new</TT>(placement <TT>new</TT>)”,为什么要用它 ?</H3></DIV>
<P>定位放置<TT>new</TT>(placement <TT>new</TT>)有很多作用。最简单的用处就是将对象放置在内存中的特殊位置。这是依靠 
<TT>new</TT>表达式部分的指针参数的位置来完成的:
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;#include&nbsp;&lt;new&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;必须&nbsp;<TT>#include</TT>&nbsp;这个,才能使用&nbsp;"placement&nbsp;<TT>new</TT>"</EM><TT><BR>&nbsp;#include&nbsp;"Fred.h"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;<TT>class</TT>&nbsp;<TT>Fred 
的声明</TT></EM><TT><BR>&nbsp;<BR>&nbsp;void&nbsp;someCode()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;char&nbsp;memory[sizeof(Fred)];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;Line&nbsp;#1</EM><TT><BR>&nbsp;&nbsp;&nbsp;void*&nbsp;place&nbsp;=&nbsp;memory;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;Line&nbsp;#2</EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;Fred*&nbsp;f&nbsp;=&nbsp;new(place)&nbsp;Fred();&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;Line&nbsp;#3&nbsp;(详见以下的“危险”)</EM><TT><BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;The&nbsp;pointers&nbsp;<TT>f</TT>&nbsp;and&nbsp;<TT>place</TT>&nbsp;will&nbsp;be&nbsp;equal</EM><TT><BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;} 
</TT></DIV>
<P>Line #1 在内存中创建了一个<TT>sizeof(Fred)</TT>字节大小的数组,足够放下 <TT>Fred </TT>对象。Line #2 
创建了一个指向这块内存的首字节的<TT>place</TT>指针(有经验的 C 程序员会注意到这一步是多余的,这儿只是为了使代码更明显)。Line #3 
本质上只是调用了构造函数 
<TT>Fred::Fred()</TT>。<TT>Fred</TT>构造函数中的<TT>this</TT>指针将等于<TT>place</TT>。因此返回的 
<TT>f </TT>将等于<TT>place</TT>。 
<P>建议:万不得已时才使用“placement 
<TT>new</TT>”语法。只有当你真的在意对象在内存中的特定位置时才使用它。例如,你的硬件有一个内存映象的 
I/O计时器设备,并且你想放置一个<TT>Clock</TT>对象在那个内存位置。
<P>危险:你要独自承担这样的责任,传递给“placement 
<TT>new</TT>”操作符的指针所指向的内存区域必须足够大,并且可能需要为所创建的对象进行边界调整。编译器和运行时系统都不会进行任何的尝试来检查你做的是否正确。如果 
<TT>Fred</TT><TT> 
</TT>类需要将边界调整为4字节,而你提供的位置没有进行边界调整的话,你就会亲手制造一个严重的灾难(如果你不明白“边界调整”的意思,那么就不要使用placement 
<TT>new</TT>语法)。
<P>你还有析构放置的对象的责任。这通过显式调用析构函数来完成: 
<P>
<DIV 
class=CodeBlock><TT>&nbsp;void&nbsp;someCode()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;char&nbsp;memory[sizeof(Fred)];<BR>&nbsp;&nbsp;&nbsp;void*&nbsp;p&nbsp;=&nbsp;memory;<BR>&nbsp;&nbsp;&nbsp;Fred*&nbsp;f&nbsp;=&nbsp;new(p)&nbsp;Fred();<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;&nbsp;&nbsp;f-&gt;~Fred();&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;显式调用定位放置的对象的析构函数</EM><TT><BR>&nbsp;} 
</TT></DIV>
<P>这是显式调用析构函数的唯一时机。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[11.11]></A>
<DIV class=FaqTitle>
<H3>[11.11] 编写析构函数时,需要显式调用成员对象的析构函数吗?</H3></DIV>
<P>不!永远不需要显式调用析构函数(除了<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#[11.10]">定位放置 
<TT>new</TT></A>的情况)。 
<P>类的析构函数(不论你是否显式地定义了)自动调用成员对象的析构函数。它们以出现在类声明中的顺序的反序被析构。 
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;class&nbsp;Member&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;~Member();<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;};<BR>&nbsp;<BR>&nbsp;class&nbsp;Fred&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;~Fred();<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;Member&nbsp;x_;<BR>&nbsp;&nbsp;&nbsp;Member&nbsp;y_;<BR>&nbsp;&nbsp;&nbsp;Member&nbsp;z_;<BR>&nbsp;};<BR>&nbsp;<BR>&nbsp;Fred::~Fred()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;编译器自动调用&nbsp;<TT>z_.~Member()</TT></EM><TT><BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;编译器自动调用&nbsp;<TT>y_.~Member()</TT></EM><TT><BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;编译器自动调用&nbsp;<TT>x_.~Member()</TT></EM><TT><BR>&nbsp;} 
</TT></DIV>
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[11.12]></A>
<DIV class=FaqTitle>
<H3>[11.12] 当我写派生类的析构函数时,需要显式调用基类的析构函数吗?</H3></DIV>
<P>不!永远不需要显式调用析构函数(除了<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#[11.10]">定位放置 
<TT>new</TT></A>的情况)。
<P>派生类的析构函数(不论你是否显式地定义了)自动调用基类子对象的析构函数。基类在成员对象之后被析构。在多重继承的情况下,直接基类以出现在继承列表中的顺序的反序被析构。
<P> 
<DIV 
class=CodeBlock><TT>&nbsp;class&nbsp;Member&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;~Member();<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;};<BR>&nbsp;<BR>&nbsp;class&nbsp;Base&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;virtual&nbsp;~Base();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/virtual-functions.html#[20.4]">虚析构函数</A></EM><TT><BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;};<BR>&nbsp;<BR>&nbsp;class&nbsp;Derived&nbsp;:&nbsp;public&nbsp;Base&nbsp;{<BR>&nbsp;public:<BR>&nbsp;&nbsp;&nbsp;~Derived();<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;...</EM><TT><BR>&nbsp;private:<BR>&nbsp;&nbsp;&nbsp;Member&nbsp;x_;<BR>&nbsp;};<BR>&nbsp;<BR>&nbsp;Derived::~Derived()<BR>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;编译器自动调用&nbsp;<TT>x_.~Member()</TT></EM><TT><BR>&nbsp;&nbsp;&nbsp;</TT><EM>//&nbsp;编译器自动调用&nbsp;<TT>Base::~Base()</TT></EM><TT><BR>&nbsp;} 
</TT></DIV>
<P>注意:虚拟继承的顺序相关性是多变的。如果你在一个虚拟继承层次中依赖于其顺序相关性,那么你需要比这个FAQ更多的信息。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html">Next&nbsp;section</A> 
]</SMALL> 
<HR>

<P><A name=[11.13]></A>
<DIV class=FaqTitle>
<H3>[11.13] 当析构函数检测到错误时,可以抛出异常吗?<IMG alt=NEW! 
src="[11] Destructors, C++ FAQ Lite.files/new.gif"></H3></DIV><SMALL><EM>[Recently 
created (on 7/00). <A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.html#[12.3]">Click 
here to go to the next FAQ in the "chain" of recent changes<!--rawtext:[12.3]:rawtext--></A>.]</EM></SMALL> 
<P>谨防!!! 详见 <A href="http://www.sunistudio.com/cppfaq/exceptions.html#[17.3]">该 
FAQ<!--rawtext:[17.3]:rawtext--></A>。 
<P><SMALL>[&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#top">Top</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/dtors.html#bottom">Bottom</A> |&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/ctors.html">Previous&nbsp;section</A> 
|&nbsp;<A 
href="http://www.sunistudio.com/cppfaq/assignment-operators.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="[11] Destructors, 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 + -