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

📄 mi9.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<TITLE>More Effective C++ | Item 9: Use destructors to prevent resource leaks</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 2; setCurrentMax(2);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript" SRC="../JAVA/IMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript" SRC="../JAVA/NSIMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var dingbase = "MI9_DIR.HTM";
var dingtext = "Item M9, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName = "M9: Use destructors to prevent resource leaks" -->
<A NAME="5292"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MEXCEPFR.HTM" TARGET="_top">Exceptions</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MI10_FR.HTM" TARGET="_top">Item 10: Prevent resource leaks in constructors</A></FONT></DIV>



<P><A NAME="dingp1"></A><font ID="mititle">Item 9: &nbsp;Use destructors to prevent resource leaks.</font><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="72119"></A><A NAME="38385"></A>
<P><A NAME="dingp2"></A>
Say good-bye to pointers. Admit it: you never really liked them that much <NOBR>anyway.<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>
<A NAME="38394"></A>
<P><A NAME="dingp3"></A>
Okay, you don't have to say good-bye to <I>all</I> pointers, but you do need to say <I>sayonara</I> to pointers that are used to manipulate local resources. Suppose, for example, you're writing software at the Shelter for Adorable Little Animals, an organization that finds homes for puppies and kittens. Each day the shelter creates a file containing information on the adoptions it arranged that day, and your job is to write a program to read these files and do the appropriate processing for each <NOBR>adoption.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P><A NAME="69161"></A>

<P><A NAME="dingp4"></A>A reasonable approach to this task is to define an abstract base class, <CODE>ALA</CODE> ("Adorable Little Animal"), plus concrete derived classes for puppies and kittens. A virtual function, <CODE>processAdoption</CODE>, handles the necessary species-specific <NOBR>processing:<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>

<SPAN ID="Image1of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_045A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_045A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_045A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_045A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_045A5.GIF" BORDER=0></SPAN>

<SPAN ID="Image1of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_045A5.GIF" BORDER=0></SPAN>

<A NAME="69179"></A>
<UL><PRE><A NAME="p46"></A>class ALA {
public:
  virtual void processAdoption() = 0;
  ...
};
</PRE>
</UL><A NAME="69182"></A>
<UL><PRE>class Puppy: public ALA {
public:
  virtual void processAdoption();
  ...
};
</PRE>
</UL><A NAME="69190"></A>
<UL><PRE>class Kitten: public ALA {
public:
  virtual void processAdoption();
  ...
};
</PRE>
</UL><A NAME="69188"></A>
<P><A NAME="dingp5"></A>You'll need a function that can read information from a file and produce either a <CODE>Puppy</CODE> object or a <CODE>Kitten</CODE> object, depending on the information in the file. This is a perfect job for a <I>virtual constructor</I>, a kind of function described in <a href="./MI25_FR.HTM#5341" TARGET="_top">Item 25</A>. For our purposes here, the function's declaration is all we <NOBR>need:<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="69233"></A>

<UL><PRE>// read animal information from s, then return a pointer
// to a newly allocated object of the appropriate type
ALA * readALA(istream&amp; s);
</PRE>
</UL><A NAME="69229"></A>

<P><A NAME="dingp6"></A>The heart of your program is likely to be a function that looks something like <NOBR>this:<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>
<A NAME="69239"></A>
<UL><PRE>void processAdoptions(istream&amp; dataSource)
{
  while (dataSource) {                  // while there's data
    ALA *pa = readALA(dataSource);      // get next animal
    pa-&gt;processAdoption();              // process adoption
    delete pa;                          // delete object that
  }                                     // readALA returned
}
</PRE>
</UL><A NAME="69180"></A>

<P><A NAME="dingp7"></A>This function loops through the information in <CODE>dataSource</CODE>, processing each entry as it goes. The only mildly tricky thing is the need to remember to delete <CODE>pa</CODE> at the end of each iteration. This is necessary because <CODE>readALA</CODE> creates a new heap object each time it's called. Without the call to <CODE>delete</CODE>, the loop would contain a resource <NOBR>leak.<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P><A NAME="69244"></A>

<P><A NAME="dingp8"></A>Now consider what would happen if <CODE>pa-&gt;processAdoption</CODE> threw an exception. <CODE>processAdoptions</CODE> fails to catch exceptions, so the exception would propagate to <CODE>processAdoptions</CODE>'s caller. In doing so, all statements in <CODE>processAdoptions</CODE> after the call to <CODE>pa-&gt;processAdoption</CODE> would be skipped, and that means <CODE>pa</CODE> would never be deleted. As <A NAME="p47"></A>a result, anytime <CODE>pa-&gt;processAdoption</CODE> throws an exception, <CODE>processAdoptions</CODE> contains a resource <NOBR>leak.<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P><A NAME="38462"></A>

<P><A NAME="dingp9"></A>Plugging the leak is easy <NOBR>enough,<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<A NAME="69309"></A>
<UL><PRE>void processAdoptions(istream&amp; dataSource)
{
  while (dataSource) {
    ALA *pa = readALA(dataSource);
</PRE>
</UL><A NAME="69316"></A>
<UL><PRE>  try {
      pa-&gt;processAdoption();
  }
  catch (...) {              // catch all exceptions
</PRE>
</UL><A NAME="69364"></A>
<UL><PRE>
    delete pa;               // avoid resource leak when an
                             // exception is thrown
</PRE>
</UL><A NAME="69326"></A>
<UL><PRE>
    throw;                   // propagate exception to caller
  }
</PRE>
</UL><A NAME="69332"></A>
<UL><PRE>
  delete pa;                 // avoid resource leak when no
 }                           // exception is thrown
}
</PRE>
</UL><A NAME="38463"></A>

<P><A NAME="dingp10"></A>but then you have to litter your code with <CODE>try</CODE> and <CODE>catch</CODE> blocks. More importantly, you are forced to duplicate cleanup code that is common to both normal and exceptional paths of control. In this case, the call to <CODE>delete</CODE> must be duplicated. Like all replicated code, this is annoying to write and difficult to maintain, but it also <I>feels wrong</I>. Regardless of whether we leave <CODE>processAdoptions</CODE> by a normal return or by throwing an exception, we need to delete <CODE>pa</CODE>, so why should we have to say that in more than one <NOBR>place?<SCRIPT>create_link(10);</SCRIPT>

⌨️ 快捷键说明

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