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

📄 mi29.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 5 页
字号:
The first constructor is implemented about as simply as possible. We use the passed-in <CODE>char*</CODE> string to create a new <CODE>StringValue</CODE> object, then we make the <CODE>String</CODE> object we're constructing point to the newly-minted <CODE>StringValue</CODE>:<SCRIPT>create_link(19);</SCRIPT>
</P><A NAME="16092"></A>
<UL><PRE>String::String(const char *initValue)
: value(new StringValue(initValue))
{}
</PRE>
</UL><P><A NAME="16126"></A>
<A NAME="dingp20"></A>For client code that looks like <NOBR>this,<SCRIPT>create_link(20);</SCRIPT>
</NOBR></P><A NAME="16127"></A>
<UL><PRE>String s("More Effective C++");
</PRE>
</UL><P><A NAME="dingp21"></A><A NAME="16128"></A>
we end up with a data structure that looks like <NOBR>this:<SCRIPT>create_link(21);</SCRIPT>
</NOBR></P>

<SPAN ID="Image4of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_187A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image4of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_187A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image4of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_187A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image4of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_187A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image4of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_187A5.GIF" BORDER=0></SPAN>

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

<P><A NAME="dingp22"></A><A NAME="16129"></A>
<CODE>String</CODE> objects constructed separately, but with the same initial value do not share a data structure, so client code of this <NOBR>form,<SCRIPT>create_link(22);</SCRIPT>
</NOBR></P><A NAME="16201"></A>
<UL><PRE>String s1("More Effective C++");
String s2("More Effective C++");
</PRE>
</UL><P><A NAME="dingp23"></A><A NAME="16204"></A>
yields this data <NOBR>structure:<SCRIPT>create_link(23);</SCRIPT>
</NOBR></P>

<SPAN ID="Image5of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_187B1.GIF" BORDER=0></SPAN>
<SPAN ID="Image5of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_187B2.GIF" BORDER=0></SPAN>
<SPAN ID="Image5of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_187B3.GIF" BORDER=0></SPAN>
<SPAN ID="Image5of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_187B4.GIF" BORDER=0></SPAN>
<SPAN ID="Image5of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_187B5.GIF" BORDER=0></SPAN>

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

<P><A NAME="dingp24"></A><A NAME="16199"></A>
It is possible to eliminate such duplication by having <CODE>String</CODE> (or <CODE>StringValue</CODE>) keep track of existing <CODE>StringValue</CODE> objects and create new ones only for truly unique strings, but such refinements on refer<A NAME="p188"></A>ence counting are somewhat off the beaten path. As a result, I'll leave them in the form of the feared and hated exercise for the <NOBR>reader.<SCRIPT>create_link(24);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp25"></A><A NAME="16247"></A>
The <CODE>String</CODE> copy constructor is not only unfeared and unhated, it's also efficient: the newly created <CODE>String</CODE> object shares the same <CODE>StringValue</CODE> object as the <CODE>String</CODE> object that's being <NOBR>copied:<SCRIPT>create_link(25);</SCRIPT>
</NOBR></P><A NAME="16093"></A>
<UL><PRE>String::String(const String&amp; rhs)
: value(rhs.value)
{
  ++value-&gt;refCount;
}
</PRE>
</UL>
<P><A NAME="dingp26"></A><A NAME="16088"></A>
Graphically, code like <NOBR>this,<SCRIPT>create_link(26);</SCRIPT>
</NOBR></P><A NAME="16258"></A>
<UL><PRE>String s1("More Effective C++");
String s2 = s1;
</PRE>
</UL><P><A NAME="dingp27"></A><A NAME="16261"></A>
results in this data <NOBR>structure:<SCRIPT>create_link(27);</SCRIPT>
</NOBR></P>

<SPAN ID="Image6of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_188A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_188A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_188A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_188A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image6of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_188A5.GIF" BORDER=0></SPAN>

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

<P><A NAME="dingp28"></A><A NAME="16256"></A>
This is substantially more efficient than a conventional (non-reference-counted) <CODE>String</CODE> class, because there is no need to allocate memory for the second copy of the string value, no need to deallocate that memory later, and no need to copy the value that would go in that memory. Instead, we merely copy a pointer and increment a reference <NOBR>count.<SCRIPT>create_link(28);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp29"></A><A NAME="16295"></A>
The <CODE>String</CODE> destructor is also easy to implement, because most of the time it doesn't do anything. As long as the reference count for a <CODE>StringValue</CODE> is non-zero, at least one <CODE>String</CODE> object is using the value; it must therefore not be destroyed. Only when the <CODE>String</CODE> being destructed is the sole user of the value &#151; i.e., when the value's reference count is 1 &#151; should the <CODE>String</CODE> destructor destroy the <CODE>StringValue</CODE> <NOBR>object:<SCRIPT>create_link(29);</SCRIPT>
</NOBR></P><A NAME="16329"></A>
<UL><PRE>class String {
public:
  ~String();
  ...
};
</PRE>
</UL><A NAME="16323"></A>
<UL><PRE>String::~String()
{
  if (--value-&gt;refCount == 0) delete value;
}
</PRE>
</UL>
<P><A NAME="dingp30"></A><A NAME="16359"></A>
<A NAME="p189"></A>Compare the efficiency of this function with that of the destructor for a non-reference-counted implementation. Such a function would always call <CODE>delete</CODE> and would almost certainly have a nontrivial runtime cost. Provided that different <CODE>String</CODE> objects do in fact sometimes have the same values, the implementation above will sometimes do nothing more than decrement a counter and compare it to <NOBR>zero.<SCRIPT>create_link(30);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp31"></A><A NAME="52490"></A>
If, at this point, the appeal of reference counting is not becoming apparent, you're just not paying <NOBR>attention.<SCRIPT>create_link(31);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp32"></A><A NAME="16363"></A>
That's all there is to <CODE>String</CODE> construction and destruction, so we'll move on to consideration of the <CODE>String</CODE> assignment <NOBR>operator:<SCRIPT>create_link(32);</SCRIPT>
</NOBR></P><A NAME="16383"></A>
<UL><PRE>class String {
public:
  String&amp; operator=(const String&amp; rhs);
  ...
</PRE>
</UL><A NAME="16384"></A>
<UL><PRE>};
</PRE>
</UL>
<P><A NAME="dingp33"></A><A NAME="16377"></A>
When a client writes code like <NOBR>this,<SCRIPT>create_link(33);</SCRIPT>
</NOBR></P><A NAME="16400"></A>
<UL><PRE>s1 = s2;                              // s1 and s2 are both String objects
</PRE>
</UL>
<P><A NAME="dingp34"></A><A NAME="16360"></A>
the result of the assignment should be that <CODE>s1</CODE> and <CODE>s2</CODE> both point to the same <CODE>StringValue</CODE> object. That object's reference count should therefore be incremented during the assignment. Furthermore, the <CODE>StringValue</CODE> object that <CODE>s1</CODE> pointed to prior to the assignment should have its reference count decremented, because <CODE>s1</CODE> will no longer have that value. If <CODE>s1</CODE> was the only <CODE>String</CODE> with that value, the value should be destroyed. In C++, all that looks like <NOBR>this:<SCRIPT>create_link(34);</SCRIPT>
</NOBR></P><A NAME="16406"></A>
<UL><PRE>String&amp; String::operator=(const String&amp; rhs)
{
  if (value == rhs.value) {          // do nothing if the values
    return *this;                    // are already the same; this
  }                                  // subsumes the usual test of
                                     // this against &amp;rhs (see <a href="../EC/EI17_FR.HTM#2264" TARGET="_top">Item E17</A>)
<A NAME="16407"></A>
  if (--value-&gt;refCount == 0) {      // destroy *this's value if
    delete value;                    // no one else is using it
  }
<A NAME="16408"></A>
  value = rhs.value;                 // have *this share rhs's
  ++value-&gt;refCount;                 // value
<A NAME="16409"></A>
  return *this;
}
</PRE>
</UL>

<P><A NAME="dingp35"></A><FONT ID="mhtitle"><A NAME="p190"></A>Copy-on-Write</FONT><SCRIPT>create_link(35);</SCRIPT>
</P>

<P><A NAME="dingp36"></A><A NAME="16086"></A>
To round out our examination of reference-counted strings, consider an array-bracket operator (<CODE>[]</CODE>), which allows individual characters within strings to be read and <NOBR>written:<SCRIPT>create_link(36);</SCRIPT>
</NOBR></P><A NAME="16445"></A>
<UL><PRE>class String {
public:
  const char&amp;
    operator[](int index) const;       // for const Strings
<A NAME="10534"></A>
  char&amp; operator[](int index);           // for non-const Strings
<A NAME="7487"></A>
...
<A NAME="16447"></A>
};
</PRE>
</UL>

<P><A NAME="dingp37"></A><A NAME="16485"></A>
Implementation of the <CODE>const</CODE> version of this function is straightforward, because it's a read-only operation; the value of the string can't be <NOBR>affected:<SCRIPT>create_link(37);</SCRIPT>
</NOBR></P><A NAME="16486"></A>
<UL><PRE>const char&amp; String::operator[](int index) const
{
  return value-&gt;data[index];
}
</PRE>
</UL>

<P><A NAME="dingp38"></A><A NAME="16490"></A>
(This function performs sanity checking on <CODE>index</CODE> in the grand C++ tradition, which is to say not at all. As usual, if you'd like a greater degree of parameter validation, it's easy to <NOBR>add.)<SCRIPT>create_link(38);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp39"></A><A NAME="16492"></A>
The non-<CODE>const</CODE> version of <CODE>operator[]</CODE> is a completely different story. This function may be called to read a character, but it might be called to write one, <NOBR>too:<SCRIPT>create_link(39);</SCRIPT>
</NOBR></P><A NAME="16500"></A>
<UL><PRE>String s;
<A NAME="16508"></A>
...
<A NAME="16496"></A>
cout &lt;&lt; s[3];                        // this is a read
s[5] = 'x';                          // this is a write
</PRE>
</UL>

<P><A NAME="dingp40"></A><A NAME="16494"></A>
We'd like to deal with reads and writes differently. A simple read can be dealt with in the same way as the <CODE>const</CODE> version of <CODE>operator[]</CODE> above, but a write must be implemented in quite a different <NOBR>fashion.<SCRIPT>create_link(40);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp41"></A><A NAME="16493"></A>
When we modify a <CODE>String</CODE>'s value, we have to be careful to avoid modifying the value of other <CODE>String</CODE> objects that happen to be sharing the same <CODE>StringValue</CODE> object. Unfortunately, there is no way for C++ compilers to tell us whether a particular use of <CODE>operator[]</CODE> is for a read or a write, so we must be pessimistic and assume that <I>all</I> calls to the non-<CODE>const</CODE> <CODE>operator[]</CODE> are for writes. (Proxy classes can help us differentiate reads from writes &#151; see <a href="./MI30_FR.HTM#6074" TARGET="_top">Item 30</A>.)<SCRIPT>create_link(41);</SCRIPT>
</P>
<P><A NAME="dingp42"></A><A NAME="16561"></A>
To implement the non-<CODE>const</CODE> <CODE>operator[]</CODE> safely, we must ensure that no other <CODE>String</CODE> object shares the <CODE>StringValue</CODE> to be modified by the <A NAME="p191"></A>presumed write. In short, we must ensure that the reference count for a <CODE>String</CODE>'s <CODE>StringValue</CODE> object is exactly one any time we return a reference to a character inside that <CODE>StringValue</CODE> object. Here's how we do <NOBR>it:<SCRIPT>create_link(42);</SCRIPT>
</NOBR></P><A NAME="16539"></A>

⌨️ 快捷键说明

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