📄 mi29.htm
字号:
<!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 29: Reference counting</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 12; setCurrentMax(12);</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 = "MI29_DIR.HTM";
var dingtext = "Item M29, P";
if (self == top) {
top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="M29: Reference counting" -->
<A NAME="6073"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI28_FR.HTM" TARGET="_top">Item 28: Smart pointers</A><BR>Continue to <A HREF="./MI30_FR.HTM" TARGET="_top">Item 30: Proxy classes</A></FONT></DIV>
<A NAME="p183"></A>
<P><A NAME="dingp1"></A><font ID="mititle">Item 29: Reference counting.</font><SCRIPT>create_link(1);</SCRIPT>
</P>
<A NAME="72181"></A>
<P><A NAME="dingp2"></A><A NAME="38057"></A>
Reference counting is a technique that allows multiple objects with the same value to share a single representation of that value. There are two common motivations for the technique. The first is to simplify the bookkeeping surrounding heap objects. Once an object is allocated by calling <CODE>new</CODE>, it's crucial to keep track of who <i>owns</i> that object, because the owner — and only the owner — is responsible for calling <CODE>delete</CODE> on it. But ownership can be transferred from object to object as a program runs (by passing pointers as parameters, for example), so keeping track of an object's ownership is hard work. Classes like <CODE>auto_ptr</CODE> (see <a href="./MI9_FR.HTM#5292" TARGET="_top">Item 9</A>) can help with this task, but experience has shown that most programs still fail to get it right. Reference counting eliminates the burden of tracking object ownership, because when an object employs reference counting, it owns itself. When nobody is using it any longer, it destroys itself automatically. Thus, reference counting constitutes a simple form of garbage <NOBR>collection.<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp3"></A><A NAME="15494"></A>
The second motivation for reference counting is simple common sense. If many objects have the same value, it's silly to store that value more than once. Instead, it's better to let all the objects with that value share its representation. Doing so not only saves memory, it also leads to faster-running programs, because there's no need to construct and destruct redundant copies of the same object <NOBR>value.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp4"></A><A NAME="15774"></A>
Like most simple ideas, this one hovers above a sea of interesting details. God may or may not be in the details, but successful implementations of reference counting certainly are. Before delving into details, however, let us master basics. A good way to begin is by seeing how we might come to have many objects with the same value in the first place. Here's one <NOBR>way:<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P><A NAME="57733"></A>
<UL><PRE>
class String { // the standard string type may
public: // employ the techniques in this
// Item, but that is not required
<A NAME="71997"></A>
String(const char *value = "");
String& operator=(const String& rhs);
...
<A NAME="57736"></A>
private:
char *data;
};
<A NAME="15554"></A>
String a, b, c, d, e;
<A NAME="15563"></A>
a = b = c = d = e = "Hello";
</PRE>
</UL>
<P><A NAME="dingp5"></A><A NAME="15565"></A>
It should be apparent that objects <CODE>a</CODE> through <CODE>e</CODE> all have the same value, namely <CODE>"Hello"</CODE>. How that value is represented depends on how the <A NAME="p184"></A><CODE>String</CODE> class is implemented, but a common implementation would have each <CODE>String</CODE> object carry its own copy of the value. For example, <CODE>String</CODE>'s assignment operator might be implemented like <NOBR>this:<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P><A NAME="15596"></A>
<UL><PRE>String& String::operator=(const String& rhs)
{
if (this == &rhs) return *this; // see <a href="../EC/EI17_FR.HTM#2264" TARGET="_top">Item E17</A>
<A NAME="15604"></A>
delete [] data;
data = new char[strlen(rhs.data) + 1];
strcpy(data, rhs.data);
<A NAME="15590"></A>
return *this; // see <a href="../EC/EI15_FR.HTM#2182" TARGET="_top">Item E15</A>
}
</PRE>
</UL>
<P><A NAME="dingp6"></A><A NAME="15583"></A>
Given this implementation, we can envision the five objects and their values as <NOBR>follows:<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>
<SPAN ID="Image1of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184A5.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184A5.GIF" BORDER=0></SPAN>
<P><A NAME="dingp7"></A><A NAME="15614"></A>
The redundancy in this approach is clear. In an ideal world, we'd like to change the picture to look like <NOBR>this:<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P>
<SPAN ID="Image2of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184B1.GIF" BORDER=0></SPAN>
<SPAN ID="Image2of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184B2.GIF" BORDER=0></SPAN>
<SPAN ID="Image2of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184B3.GIF" BORDER=0></SPAN>
<SPAN ID="Image2of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184B4.GIF" BORDER=0></SPAN>
<SPAN ID="Image2of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184B5.GIF" BORDER=0></SPAN>
<SPAN ID="Image2of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_184B5.GIF" BORDER=0></SPAN>
<P><A NAME="dingp8"></A><A NAME="15509"></A>
Here only one copy of the value <CODE>"Hello"</CODE> is stored, and all the <CODE>String</CODE> objects with that value share its <NOBR>representation.<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp9"></A><A NAME="15786"></A>
In practice, it isn't possible to achieve this ideal, because we need to keep track of how many objects are sharing a value. If object <CODE>a</CODE> above is assigned a different value from <CODE>"Hello"</CODE>, we can't destroy the value <CODE>"Hello"</CODE>, because four other objects still need it. On the other hand, if only a single object had the value <CODE>"Hello"</CODE> and that object went out of scope, no object would have that value and we'd have to destroy the value to avoid a resource <NOBR>leak.<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp10"></A><A NAME="15744"></A>
<A NAME="p185"></A>The need to store information on the number of objects currently sharing — <I>referring to</I> — a value means our ideal picture must be modified somewhat to take into account the existence of a <I>reference count</I>:<SCRIPT>create_link(10);</SCRIPT>
</P>
<SPAN ID="Image3of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_185A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image3of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_185A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image3of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_185A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image3of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_185A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image3of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_185A5.GIF" BORDER=0></SPAN>
<SPAN ID="Image3of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_185A5.GIF" BORDER=0></SPAN>
<P><A NAME="dingp11"></A><A NAME="11973"></A>
(Some people call this number a <I>use count</I>, but I am not one of them. C++ has enough idiosyncrasies of its own; the last thing it needs is terminological <NOBR>factionalism.)<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp12"></A>
<FONT ID="mhtitle">Implementing Reference Counting</FONT><SCRIPT>create_link(12);</SCRIPT>
</P>
<P><A NAME="dingp13"></A><A NAME="15883"></A>
Creating a reference-counted <CODE>String</CODE> class isn't difficult, but it does require attention to detail, so we'll walk through the implementation of the most common member functions of such a class. Before we do that, however, it's important to recognize that we need a place to store the reference count for each <CODE>String</CODE> value. That place cannot be in a <CODE>String</CODE> object, because we need one reference count per string <I>value</I>, not one reference count per string <I>object</I>. That implies a coupling between values and reference counts, so we'll create a class to store reference counts and the values they track. We'll call this class <CODE>StringValue</CODE>, and because its only <I>raison d'être</I> is to help implement the <CODE>String</CODE> class, we'll nest it inside <CODE>String</CODE>'s private section. Furthermore, it will be convenient to give all the member functions of <CODE>String</CODE> full access to the <CODE>StringValue</CODE> data structure, so we'll declare <CODE>StringValue</CODE> to be a <CODE>struct</CODE>. This is a trick worth knowing: nesting a struct in the private part of a class is a convenient way to give access to the struct to all the members of the class, but to deny access to everybody else (except, of course, friends of the <NOBR>class).<SCRIPT>create_link(13);</SCRIPT>
</NOBR></P> <P><A NAME="dingp14"></A><A NAME="15909"></A>
Our basic design looks like <NOBR>this:<SCRIPT>create_link(14);</SCRIPT>
</NOBR></P><A NAME="15910"></A>
<UL><PRE><A NAME="p186"></A>class String {
public:
... // the usual String member
// functions go here
<A NAME="7583"></A>
private:
struct StringValue { ... }; // holds a reference count
// and a string value
<A NAME="57747"></A>
StringValue *value; // value of this String
};
</PRE>
</UL>
<P><A NAME="dingp15"></A><A NAME="85345"></A>
We could give this class a different name (<CODE>RCString</CODE>, perhaps) to emphasize that it's implemented using reference counting, but the implementation of a class shouldn't be of concern to clients of that class. Rather, clients should interest themselves only in a class's public interface. Our reference-counting implementation of the <CODE>String</CODE> interface supports exactly the same operations as a non-reference-counted version, so why muddy the conceptual waters by embedding implementation decisions in the names of classes that correspond to abstract concepts? Why indeed? So we <NOBR>don't.<SCRIPT>create_link(15);</SCRIPT>
</NOBR></P> <P><A NAME="dingp16"></A><A NAME="15908"></A>
Here's <CODE>StringValue</CODE>:<SCRIPT>create_link(16);</SCRIPT>
</P><A NAME="15986"></A>
<UL><PRE>class String {
private:
struct StringValue {
int refCount;
char *data;
<A NAME="15990"></A>
StringValue(const char *initValue);
~StringValue();
<A NAME="16006"></A>
};
<A NAME="16007"></A>
...
<A NAME="16008"></A>
};
<A NAME="15998"></A>
String::StringValue::StringValue(const char *initValue)
: refCount(1)
{
data = new char[strlen(initValue) + 1];
strcpy(data, initValue);
}
</PRE>
</UL><A NAME="15999"></A>
<UL><PRE>String::StringValue::~StringValue()
{
delete [] data;
}
</PRE>
</UL><P><A NAME="dingp17"></A><A NAME="15985"></A>
That's all there is to it, and it should be clear that's nowhere near enough to implement the full functionality of a reference-counted string. For one thing, there's neither a copy constructor nor an assign<A NAME="p187"></A>ment operator (see <a href="../EC/EI11_FR.HTM#2042" TARGET="_top">Item E11</A>), and for another, there's no manipulation of the <CODE>refCount</CODE> field. Worry not — the missing functionality will be provided by the <CODE>String</CODE> class. The primary purpose of <CODE>StringValue</CODE> is to give us a place to associate a particular value with a count of the number of <CODE>String</CODE> objects sharing that value. <CODE>StringValue</CODE> gives us that, and that's <NOBR>enough.<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp18"></A><A NAME="15884"></A>
We're now ready to walk our way through <CODE>String</CODE>'s member functions. We'll begin with the <NOBR>constructors:<SCRIPT>create_link(18);</SCRIPT>
</NOBR></P><A NAME="80728"></A>
<UL><PRE>class String {
public:
String(const char *initValue = "");
String(const String& rhs);
</PRE>
</UL><A NAME="16101"></A>
<UL><PRE> ...
</PRE>
</UL><A NAME="16102"></A>
<UL><PRE>};
</PRE>
</UL>
<P><A NAME="dingp19"></A><A NAME="16105"></A>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -