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

📄 mi28.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<!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 28: Smart pointers</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 4; setCurrentMax(4);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/IMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/NSIMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "MI28_DIR.HTM";
var dingtext = "Item M28, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="M28: Smart pointers" -->
<A NAME="61766"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI27_FR.HTM" TARGET="_top">Item 27: Requiring or prohibiting heap-based objects</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MI29_FR.HTM" TARGET="_top">Item 29: Reference counting</A></FONT></DIV>

<A NAME="p159"></A>
<P><A NAME="dingp1"></A><font ID="mititle">Item 28: &nbsp;Smart pointers.</font><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="72179"></A>
<A NAME="61767"></A>
<P><A NAME="dingp2"></A><I>Smart pointers</I> are objects that are designed to look, act, and feel like built-in pointers, but to offer greater functionality. They have a variety of applications, including resource management (see Items <a href="./MI9_FR.HTM#5292" TARGET="_top">9</A>, <a href="./MI10_FR.HTM#38223" TARGET="_top">10</A>, <a href="./MI25_FR.HTM#5341" TARGET="_top">25</A>, and <a href="./MI31_FR.HTM#34883" TARGET="_top">31</A>) and the automation of repetitive coding tasks (see Items <a href="./MI17_FR.HTM#41011" TARGET="_top">17</A> and <a href="./MI29_FR.HTM#6073" TARGET="_top">29</A>).<SCRIPT>create_link(2);</SCRIPT>
</P><A NAME="61783"></A>

<P><A NAME="dingp3"></A>When you use smart pointers in place of C++'s built-in pointers (i.e., <I>dumb</I> pointers), you gain control over the following aspects of pointer <NOBR>behavior:<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>

<UL><A NAME="61784"></A>
<B><A NAME="dingp4"></A><LI>Construction and destruction.</B> You determine what happens when a smart pointer is created and destroyed. It is common to give smart pointers a default value of 0 to avoid the headaches associated with uninitialized pointers. Some smart pointers are made responsible for deleting the object they point to when the last smart pointer pointing to the object is destroyed. This can go a long way toward eliminating resource leaks.<SCRIPT>create_link(4);</SCRIPT>


<A NAME="61785"></A>

<B><A NAME="dingp5"></A><LI>Copying and assignment.</B> You control what happens when a smart pointer is copied or is involved in an assignment. For some smart pointer types, the desired behavior is to automatically copy or make an assignment to what is pointed to, i.e., to perform a deep copy. For others, only the pointer itself should be copied or assigned. For still others, these operations should not be allowed at all. Regardless of what behavior you consider "right," the use of smart pointers lets you call the shots.<SCRIPT>create_link(5);</SCRIPT>

<A NAME="61786"></A>

<B><A NAME="dingp6"></A><LI>Dereferencing.</B> What should happen when a client refers to the object pointed to by a smart pointer? You get to decide. You could, for example, use smart pointers to help implement the lazy fetching strategy outlined in <A HREF="./MI17_FR.HTM#41011" TARGET="_top">Item 17</A>.<SCRIPT>create_link(6);</SCRIPT>

</UL>
<A NAME="61790"></A>

<P><A NAME="dingp7"></A>Smart pointers are generated from templates because, like built-in pointers, they must be strongly typed; the template parameter specifies the type of object pointed to. Most smart pointer templates look something like <NOBR>this:<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P>

<A NAME="61791"></A>
<UL><PRE><A NAME="p160"></A>
template&lt;class T&gt;                    // template for smart
class SmartPtr {                     // pointer objects
public:
  SmartPtr(T* realPtr = 0);          // create a smart ptr to an
                                     // obj given a dumb ptr to
                                     // it; uninitialized ptrs
                                     // default to 0 (null)
<A NAME="61792"></A>
  SmartPtr(const SmartPtr&amp; rhs);     // copy a smart ptr
<A NAME="61793"></A>
  ~SmartPtr();                       // destroy a smart ptr
<A NAME="61794"></A>
  // make an assignment to a smart ptr
  SmartPtr&amp; operator=(const SmartPtr&amp; rhs);
<A NAME="61795"></A>
  T* operator-&gt;() const;             // dereference a smart ptr
                                     // to get at a member of
                                     // what it points to
<A NAME="61796"></A>
  T&amp; operator*() const;              // dereference a smart ptr
<A NAME="61797"></A>
private:
  T *pointee;                        // what the smart ptr
};                                   // points to
</PRE>
</UL>

<A NAME="61798"></A>
<P><A NAME="dingp8"></A>
The copy constructor and assignment operator are both shown public here. For smart pointer classes where copying and assignment are not allowed, they would typically be declared private (see <A HREF="../EC/EI27_FR.HTM#6406" TARGET="_top">Item E27</A>). The two dereferencing operators are declared <CODE>const</CODE>, because dereferencing a pointer doesn't modify it (though it may lead to modification of what the pointer points to). Finally, each smart pointer-to-<CODE>T</CODE> object is implemented by containing a dumb pointer-to-<CODE>T</CODE> within it. It is this dumb pointer that does the actual <NOBR>pointing.<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P><A NAME="61799"></A>
<P><A NAME="dingp9"></A>
Before going into the details of smart pointer implementation, it's worth seeing how clients might use smart pointers. Consider a distributed system in which some objects are local and some are remote. Access to local objects is generally simpler and faster than access to remote objects, because remote access may require remote procedure calls or some other way of communicating with a distant <NOBR>machine.<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P><A NAME="61800"></A>
<P><A NAME="dingp10"></A>
For clients writing application code, the need to handle local and remote objects differently is a nuisance. It is more convenient to have all objects appear to be located in the same place. Smart pointers allow a library to offer this <NOBR>illusion:<SCRIPT>create_link(10);</SCRIPT>
</NOBR></P>
<A NAME="61801"></A>
<UL><PRE>template&lt;class T&gt;                    // template for smart ptrs
class DBPtr {                        // to objects in a
public:                              // distributed DB
<A NAME="61802"></A>
  DBPtr(T *realPtr = 0);             // create a smart ptr to a
                                     // DB object given a local
                                     // dumb pointer to it
<A NAME="61803"></A>
<A NAME="p161"></A>
  DBPtr(DataBaseID id);              // create a smart ptr to a
                                     // DB object given its
                                     // unique DB identifier
<A NAME="61804"></A>
  ...                                // other smart ptr
};                                   // functions as above
<A NAME="61805"></A>
class Tuple {                        // class for database
public:                              // tuples
  ...
  void displayEditDialog();          // present a graphical
                                     // dialog box allowing a
                                     // user to edit the tuple
<A NAME="75805"></A>
  bool isValid() const;              // return whether *this
};                                   // passes validity check
<A NAME="61807"></A>
// class template for making log entries whenever a T
// object is modified; see below for details
template&lt;class T&gt;
class LogEntry {
public:
  LogEntry(const T&amp; objectToBeModified);
  ~LogEntry();
};
<A NAME="61808"></A>
void editTuple(DBPtr&lt;Tuple&gt;&amp; pt)
{
  LogEntry&lt;Tuple&gt; entry(*pt);        // make log entry for this
                                     // editing operation; see
                                     // below for details
<A NAME="75806"></A>
  // repeatedly display edit dialog until valid values
  // are provided
  do {
    pt-&gt;displayEditDialog();
  } while (pt-&gt;isValid() == false);
}
</PRE>
</UL>

<A NAME="61810"></A>
<P><A NAME="dingp11"></A>
The tuple to be edited inside <CODE>editTuple</CODE> may be physically located on a remote machine, but the programmer writing <CODE>editTuple</CODE> need not be concerned with such matters; the smart pointer class hides that aspect of the system. As far as the programmer is concerned, all tuples are accessed through objects that, except for how they're declared, act just like run-of-the-mill built-in <NOBR>pointers.<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P><A NAME="61811"></A>
<P><A NAME="dingp12"></A>
Notice the use of a <CODE>LogEntry</CODE> object in <CODE>editTuple</CODE>. A more conventional design would have been to surround the call to <CODE>displayEditDialog</CODE> with calls to begin and end the log entry. In the approach shown here, the <CODE>LogEntry</CODE>'s constructor begins the log entry and its destructor ends the log entry. As <A HREF="./MI9_FR.HTM#5292" TARGET="_top">Item 9</A> explains, using an object to begin and end logging is more robust in the face of exceptions than explicitly calling functions, so you should accustom yourself to using <A NAME="p162"></A>classes like <CODE>LogEntry</CODE>. Besides, it's easier to create a single <CODE>LogEntry</CODE> object than to add separate calls to start and stop an <NOBR>entry.<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P><A NAME="61815"></A>

<P><A NAME="dingp13"></A>As you can see, using a smart pointer isn't much different from using the dumb pointer it replaces. That's testimony to the effectiveness of encapsulation. Clients of smart pointers are <I>supposed</I> to be able to treat them as dumb pointers. As we shall see, sometimes the substitution is more transparent than <NOBR>others.<SCRIPT>create_link(13);</SCRIPT>
</NOBR></P>

<P><A NAME="dingp14"></A><FONT ID="mhtitle">Construction, Assignment, and Destruction of Smart Pointers</FONT><SCRIPT>create_link(14);</SCRIPT>
</P>
<A NAME="61817"></A>
<P><A NAME="dingp15"></A>Construction of a smart pointer is usually straightforward: locate an object to point to (typically by using the smart pointer's constructor arguments), then make the smart pointer's internal dumb pointer point there. If no object can be located, set the internal pointer to 0 or signal an error (possibly by throwing an <NOBR>exception).<SCRIPT>create_link(15);</SCRIPT>
</NOBR></P><A NAME="61824"></A>
<P><A NAME="dingp16"></A>
Implementing a smart pointer's copy constructor, assignment operator(s) and destructor is complicated somewhat by the issue of <I>ownership</I>. If a smart pointer <I>owns</I> the object it points to, it is responsible for deleting that object when it (the smart pointer) is destroyed. This assumes the object pointed to by the smart pointer is dynamically allocated. Such an assumption is common when working with smart pointers. (For ideas on how to make sure the assumption is true, see <A HREF="./MI27_FR.HTM#22627" TARGET="_top">Item 27</A>.)<SCRIPT>create_link(16);</SCRIPT>
</P><A NAME="71653"></A>
<P><A NAME="dingp17"></A>
Consider the <CODE>auto_ptr</CODE> template from the standard C++ library. As <A HREF="./MI9_FR.HTM#5292" TARGET="_top">Item 9</A> explains, an <CODE>auto_ptr</CODE> object is a smart pointer that points to a heap-based object until it (the <CODE>auto_ptr</CODE>) is destroyed. When that happens, the <CODE>auto_ptr</CODE>'s destructor deletes the pointed-to object. The <CODE>auto_ptr</CODE> template might be implemented like <NOBR>this:<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>
<A NAME="61832"></A>
<UL><PRE>template&lt;class T&gt;
class auto_ptr {
public:
  auto_ptr(T *ptr = 0): pointee(ptr) {}
  ~auto_ptr() { delete pointee; }
  ...
<A NAME="61834"></A>
private:
  T *pointee;
};
</PRE>
</UL>

<A NAME="61835"></A>
<P><A NAME="dingp18"></A>
This works fine provided only one <CODE>auto_ptr</CODE> owns an object. But what should happen when an <CODE>auto_ptr</CODE> is copied or <NOBR>assigned?<SCRIPT>create_link(18);</SCRIPT>
</NOBR></P>
<A NAME="61836"></A>
<UL><PRE>auto_ptr&lt;TreeNode&gt; ptn1(new TreeNode);
<A NAME="61837"></A>

⌨️ 快捷键说明

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