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

📄 mc3.htm

📁 有基本了解的程序员或程序爱好者而做
💻 HTM
📖 第 1 页 / 共 5 页
字号:
};
</PRE>
</UL><A NAME="69425"></A>
<P><A NAME="dingp21"></A>
The standard version of <CODE>auto_ptr</CODE> is much fancier, and this stripped-down implementation isn't suitable for real use<A HREF="#74869" onMouseOver = "self.status = 'Link to Footnote 3'; return true" onMouseOut = "self.status = self.defaultStatus"><sup>3</sup></A> (we must add at least the copy constructor, assignment operator, and pointer-emulating functions discussed in <A HREF="./MC5_FR.HTM#61766" TARGET="_top" onMouseOver = "self.status = 'Link to MEC++ Item 28'; return true" onMouseOut = "self.status = self.defaultStatus">Item 28</A>), but the concept behind it should be clear: use <CODE>auto_ptr</CODE> objects instead of raw pointers, and you won't have to worry about heap objects not being deleted, not even when exceptions are thrown. (Because the <CODE>auto_ptr</CODE> destructor uses the single-object form of <CODE>delete</CODE>, <CODE>auto_ptr</CODE> is not suitable for use with pointers to <I>arrays</I> of objects. If you'd like an <CODE>auto_ptr</CODE>-like template for arrays, you'll have to write your own. In such cases, however, it's often a better design decision to use a <CODE>vector</CODE> instead of an array, <NOBR>anyway.)<SCRIPT>create_link(21);</SCRIPT>
</NOBR></P><A NAME="69464"></A>
<P><A NAME="dingp22"></A>
Using an <CODE>auto_ptr</CODE> object instead of a raw pointer, <CODE>processAdoptions</CODE> looks like <NOBR>this:<SCRIPT>create_link(22);</SCRIPT>
</NOBR></p>
<A NAME="69466"></A>
<UL><PRE>void processAdoptions(istream&amp; dataSource)
{
  while (dataSource) {
    auto_ptr&lt;ALA&gt; pa(readALA(dataSource));
    pa-&gt;processAdoption();
  }
}
</PRE>
</UL><A NAME="79353"></A>
<P><A NAME="dingp23"></A>
This version of <CODE>processAdoptions </CODE>differs from the original in only two ways. First, <CODE>pa</CODE> is declared to be an <CODE>auto_ptr&lt;ALA&gt;</CODE> object, not a raw <CODE>ALA*</CODE> pointer. Second, there is no <CODE>delete</CODE> statement at the end of the loop. That's it. Everything else is identical, because, except for destruction, <CODE>auto_ptr</CODE> objects act just like normal pointers. Easy, <NOBR>huh?<SCRIPT>create_link(23);</SCRIPT>
</NOBR></P><A NAME="79324"></A>
<A NAME="p49"></A>
<P><A NAME="dingp24"></A>
The idea behind <CODE>auto_ptr</CODE> &#151; using an object to store a resource that needs to be automatically released and relying on that object's destructor to release it &#151; applies to more than just pointer-based resources. Consider a function in a GUI application that needs to create a window to display some <NOBR>information:<SCRIPT>create_link(24);</SCRIPT>
</NOBR></p>
<A NAME="43844"></A>

<UL><PRE>// this function may leak resources if an exception
// is thrown
void displayInfo(const Information&amp; info)
{
  WINDOW_HANDLE w(createWindow());
<A NAME="43845"></A>
  <I>display info in window corresponding to w;</I>
<A NAME="43803"></A>
  destroyWindow(w);
}
</PRE>
</UL><A NAME="43798"></A>

<P><A NAME="dingp25"></A>
Many window systems have C-like interfaces that use functions like <CODE>createWindow</CODE> and <CODE>destroyWindow</CODE> to acquire and release window resources. If an exception is thrown during the process of displaying <CODE>info</CODE> in <CODE>w</CODE>, the window for which <CODE>w</CODE> is a handle will be lost just as surely as any other dynamically allocated <NOBR>resource.<SCRIPT>create_link(25);</SCRIPT>
</NOBR></P><A NAME="43903"></A>
<P><A NAME="dingp26"></A>
The solution is the same as it was before. Create a class whose constructor and destructor acquire and release the <NOBR>resource:<SCRIPT>create_link(26);</SCRIPT>
</NOBR></p>
<A NAME="43811"></A>

<UL><PRE>// class for acquiring and releasing a window handle
class WindowHandle {
public:
   WindowHandle(WINDOW_HANDLE handle): w(handle) {}
  ~WindowHandle() { destroyWindow(w); }
</PRE>
</UL><A NAME="43814"></A>
<UL><PRE>   operator WINDOW_HANDLE() { return w; }        // see below
</PRE>
</UL><A NAME="57440"></A>
<UL><PRE>private:
  WINDOW_HANDLE w;
</PRE>
</UL><A NAME="69531"></A>
<UL><PRE>
  // The following functions are declared private to prevent
  // multiple copies of a WINDOW_HANDLE from being created.
  // See <A HREF="./MC5_FR.HTM#61766" TARGET="_top" onMouseOver = "self.status = 'Link to MEC++ 28'; return true" onMouseOut = "self.status = self.defaultStatus">Item 28</A> for a discussion of a more flexible approach.
  WindowHandle(const WindowHandle&amp;);
  WindowHandle&amp; operator=(const WindowHandle&amp;);
};
</PRE>
</UL>

<A NAME="69562"></A>
<P><A NAME="dingp27"></A>
This looks just like the <CODE>auto_ptr</CODE> template, except that assignment and copying are explicitly prohibited (see <A HREF="../EC/EC4_FR.HTM#6406" TARGET="_top" onMouseOver = "self.status = 'Link to EC++ Item 27'; return true" onMouseOut = "self.status = self.defaultStatus">Item E27</A>), and there is an implicit conversion operator that can be used to turn a <CODE>WindowHandle</CODE> into a <CODE>WINDOW_HANDLE</CODE>. This capability is essential to the practical application of a <CODE>WindowHandle</CODE> object, because it means you can use a <CODE>WindowHandle</CODE> just about anywhere you would normally use a raw <CODE>WINDOW_HANDLE</CODE>. (See <A HREF="./MC2_FR.HTM#5970" TARGET="_top" onMouseOver = "self.status = 'Link to MEC++ Item 5'; return true" onMouseOut = "self.status = self.defaultStatus">Item 5</A>, however, for why you should generally be leery of implicit type conversion <NOBR>operators.)<SCRIPT>create_link(27);</SCRIPT>
</NOBR></P><A NAME="69589"></A>
<A NAME="p50"></A>
<P><A NAME="dingp28"></A>
Given the <CODE>WindowHandle</CODE> class, we can rewrite <CODE>displayInfo</CODE> as <NOBR>follows:<SCRIPT>create_link(28);</SCRIPT>
</NOBR></p>
<A NAME="43827"></A>
<UL><PRE>// this function avoids leaking resources if an
// exception is thrown
void displayInfo(const Information&amp; info)
{
  WindowHandle w(createWindow());
<A NAME="43867"></A>
  <I>display info in window corresponding to w;</I>
<A NAME="43836"></A>
}
</PRE>
</UL><A NAME="69593"></A>
<P><A NAME="dingp29"></A>
Even if an exception is thrown within <CODE>displayInfo</CODE>, the window created by <CODE>createWindow</CODE> will always be <NOBR>destroyed.<SCRIPT>create_link(29);</SCRIPT>
</NOBR></P><A NAME="43780"></A>
<P><A NAME="dingp30"></A>
By adhering to the rule that resources should be encapsulated inside objects, you can usually avoid resource leaks in the presence of exceptions. But what happens if an exception is thrown while you're in the process of acquiring a resource, e.g., while you're in the constructor of a resource-acquiring class? What happens if an exception is thrown during the automatic destruction of such resources? Don't constructors and destructors call for special techniques? They do, and you can read about them in Items <A HREF="#38223" onMouseOver = "self.status = 'Link to MEC++ Item 10'; return true" onMouseOut = "self.status = self.defaultStatus">10</A> and <A HREF="#39749" onMouseOver = "self.status = 'Link to MEC++ 11'; return true" onMouseOut = "self.status = self.defaultStatus">11</A>.<SCRIPT>create_link(30);</SCRIPT>
</p>

<!-- SectionName="M10: Prevent resource leaks in constructors" -->

<A NAME="38223"></A><DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MC3.HTM#5292">Item 9: Use destructors to prevent resource leaks</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MC3.HTM#39749">Item 11: Prevent exceptions from leaving destructors</A></FONT></DIV>
<P><A NAME="dingp31"></A><font ID="mititle">Item 10: &nbsp;Prevent resource leaks in constructors.</font><SCRIPT>create_link(31);</SCRIPT>
</P>

<A NAME="72121"></A><A NAME="38800"></A>

<P><A NAME="dingp32"></A>
Imagine you're developing software for a multimedia address book. Such an address book might hold, in addition to the usual textual information of a person's name, address, and phone numbers, a picture of the person and the sound of their voice (possibly giving the proper pronunciation of their <NOBR>name).<SCRIPT>create_link(32);</SCRIPT>
</NOBR></P><A NAME="69713"></A>
<P><A NAME="dingp33"></A>
To implement the book, you might come up with a design like <NOBR>this:<SCRIPT>create_link(33);</SCRIPT>
</NOBR></p>

<A NAME="38913"></A>
<UL><PRE>class Image {                        // for image data
public:
  Image(const string&amp; imageDataFileName);
  ...
};
<A NAME="70436"></A>
class AudioClip {                    // for audio data
public:
  AudioClip(const string&amp; audioDataFileName);
  ...
};
<A NAME="69762"></A>
class PhoneNumber {         ... };   // for holding phone numbers
<A NAME="69763"></A>
<A NAME="p51"></A>
class BookEntry {                    // for each entry in the
public:                              // address book
<A NAME="69747"></A>
BookEntry(const string&amp; name,
          const string&amp; address = "",
          const string&amp; imageFileName = "",
          const string&amp; audioClipFileName = "");
~BookEntry();
<A NAME="69879"></A>
// phone numbers are added via this function
void addPhoneNumber(const PhoneNumber&amp; number);
...
<A NAME="57457"></A>
private:
  string theName;                 // person's name
  string theAddress;              // their address
  list&lt;PhoneNumber&gt; thePhones;    // their phone numbers
  Image *theImage;                // their image
  AudioClip *theAudioClip;        // an audio clip from them
};
</PRE>
</UL><A NAME="38821"></A>

<P><A NAME="dingp34"></A>
Each <CODE>BookEntry</CODE> must have name data, so you require that as a constructor argument (see <A HREF="./MC1_FR.HTM#84818" TARGET="_top" onMouseOver = "self.status = 'Link to MEC++ Item 3'; return true" onMouseOut = "self.status = self.defaultStatus">Item 3</A>), but the other fields &#151; the person's address and the names of files containing image and audio data &#151; are optional. Note the use of the <CODE>list</CODE> class to hold the person's phone numbers. This is one of several container classes that are part of the standard C++ library (see <A HREF="../EC/EC7_FR.HTM#8392" TARGET="_top" onMouseOver = "self.status = 'Link to EC++ Item 49'; return true" onMouseOut = "self.status = self.defaultStatus">Item E49</A> and <A HREF="./MC6_FR.HTM#5473" TARGET="_top" onMouseOver = "self.status = 'Link to MEC++ Item 35'; return true" onMouseOut = "self.status = self.defaultStatus">Item 35</A>).<SCRIPT>create_link(34);</SCRIPT>
</P><A NAME="38808"></A>
<P><A NAME="dingp35"></A>
A straightforward way to write the <CODE>BookEntry</CODE> constructor and destructor is as <NOBR>follows:<SCRIPT>create_link(35);</SCRIPT>
</NOBR></p>

<A NAME="38837"></A>
<UL><PRE>BookEntry::BookEntry(const string&amp; name,
                     const string&amp; address,
                     const string&amp; imageFileName,
                     Const string&amp; audioClipFileName)
: theName(name), theAddress(address),
  theImage(0), theAudioClip(0)
{
  if (imageFileName != "") {
    theImage = new Image(imageFileName);
  }
<A NAME="69938"></A>
if (audioClipFileName != "") {
theAudioClip = new AudioClip(audioClipFileName);
  }
}
<A NAME="38845"></A>
BookEntry::~BookEntry()
{
  delete theImage;

⌨️ 快捷键说明

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