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

📄 mi19.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 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 19: Understand the origin of temporary objects</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 0; setCurrentMax(0);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>

<SCRIPT>
var dingbase = "MI19_DIR.HTM";
var dingtext = "Item M19, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="M19: Understand the origin of temporary objects" -->
<A NAME="41177"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI18_FR.HTM" TARGET="_top">Item 18: Amortize the cost of expected computations</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MI20_FR.HTM" TARGET="_top">Item 20: Facilitate the return value optimization</A></FONT></DIV>

<P><A NAME="dingp1"></A><font ID="mititle">Item 19: &nbsp;Understand the origin of temporary objects.</font><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="72148"></A><A NAME="45491"></A>
<P><A NAME="dingp2"></A>
When programmers speak amongst themselves, they often refer to variables that are needed for only a short while as "temporaries." For example, in this <CODE>swap</CODE> <NOBR>routine,<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>

<A NAME="45509"></A>
<UL><PRE><A NAME="p99"></A>template&lt;class T&gt;
void swap(T&amp; object1, T&amp; object2)
{
  T temp = object1;
  object1 = object2;
  object2 = temp;
}
</PRE>
</UL>

<A NAME="45510"></A>
<P><A NAME="dingp3"></A>it's common to call <CODE>temp</CODE> a "temporary." As far as C++ is concerned, however, <CODE>temp</CODE> is not a temporary at all. It's simply an object local to a <NOBR>function.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P><A NAME="45520"></A>
<P><A NAME="dingp4"></A>
True temporary objects in C++ are invisible &#151; they don't appear in your source code. They arise whenever a non-heap object is created but not named. Such <I>unnamed</I> objects usually arise in one of two situations: when implicit type conversions are applied to make function calls succeed and when functions return objects. It's important to understand how and why these temporary objects are created and destroyed, because the attendant costs of their construction and destruction can have a noticeable impact on the performance of your <NOBR>programs.<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P><A NAME="45532"></A>
<P><A NAME="dingp5"></A>
Consider first the case in which temporary objects are created to make function calls succeed. This happens when the type of object passed to a function is not the same as the type of the parameter to which it is being bound. For example, consider a function that counts the number of occurrences of a character in a <NOBR>string:<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>

<A NAME="45565"></A>
<UL><PRE>// returns the number of occurrences of ch in str
size_t countChar(const string&amp; str, char ch);
<A NAME="45544"></A>
char buffer[MAX_STRING_LEN];
char c;
<A NAME="45548"></A>
// read in a char and a string; use setw to avoid
// overflowing buffer when reading the string
cin &gt;&gt; c &gt;&gt; setw(MAX_STRING_LEN) &gt;&gt; buffer;
<A NAME="45578"></A>
cout &lt;&lt; "There are " &lt;&lt; countChar(buffer, c)
     &lt;&lt; " occurrences of the character " &lt;&lt; c
     &lt;&lt; " in " &lt;&lt; buffer &lt;&lt; endl;
</PRE>
</UL>

<A NAME="45579"></A>
<P><A NAME="dingp6"></A>
Look at the call to <CODE>countChar</CODE>. The first argument passed is a <CODE>char</CODE> array, but the corresponding function parameter is of type <CODE>const</CODE> <CODE>string&amp;</CODE>. This call can succeed only if the type mismatch can be eliminated, and your compilers will be happy to eliminate it by creating a temporary object of type <CODE>string</CODE>. That temporary object is initialized by calling the <CODE>string</CODE> constructor with <CODE>buffer</CODE> as its argument. The <CODE>str</CODE> parameter of <CODE>countChar</CODE> is then bound to this temporary <CODE>string</CODE> object. When <CODE>countChar</CODE> returns, the temporary object is automatically <NOBR>destroyed.<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P><A NAME="45607"></A>
<A NAME="p100"></A><P><A NAME="dingp7"></A>
Conversions such as these are convenient (though dangerous &#151; see <A HREF="./MI5_FR.HTM#5970" TARGET="_top">Item 5</A>), but from an efficiency point of view, the construction and destruction of a temporary <CODE>string</CODE> object is an unnecessary expense. There are two general ways to eliminate it. One is to redesign your code so conversions like these can't take place. That strategy is examined in <A HREF="./MI5_FR.HTM#5970" TARGET="_top">Item 5</A>. An alternative tack is to modify your software so that the conversions are unnecessary. <a href="./MI21_FR.HTM#41187" TARGET="_top">Item 21</A> describes how you can do <NOBR>that.<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P><A NAME="45763"></A>
<P><A NAME="dingp8"></A>
These conversions occur only when passing objects by value or when passing to a reference-to-<CODE>const</CODE> parameter. They do not occur when passing an object to a reference-to-non-<CODE>const</CODE> parameter. Consider this <NOBR>function:<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>
<A NAME="45764"></A>
<UL><PRE>
void uppercasify(string&amp; str);               // changes all chars in
                                             // str to upper case
</PRE>
</UL>

<A NAME="45769"></A>
<P><A NAME="dingp9"></A>
In the character-counting example, a <CODE>char</CODE> array could be successfully passed to <CODE>countChar</CODE>, but here, trying to call <CODE>uppercasify</CODE> with a <CODE>char</CODE> array <NOBR>fails:<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>

<A NAME="45782"></A>
<UL><PRE>char subtleBookPlug[] = "Effective C++";
<A NAME="45783"></A>
uppercasify(subtleBookPlug);                // error!
</PRE>
</UL>

<A NAME="45784"></A>
<P><A NAME="dingp10"></A>
No temporary is created to make the call succeed. Why <NOBR>not?<SCRIPT>create_link(10);</SCRIPT>
</NOBR></P><A NAME="45920"></A>
<P><A NAME="dingp11"></A>
Suppose a temporary were created. Then the temporary would be passed to <CODE>uppercasify</CODE>, which would modify the temporary so its characters were in upper case. But the actual argument to the function call &#151; <CODE>subtleBookPlug</CODE> &#151; would <I>not be affected</I>; only the temporary <CODE>string</CODE> object generated from <CODE>subtleBookPlug</CODE> would be changed. Surely this is not what the programmer intended. That programmer passed <CODE>subtleBookPlug</CODE> to <CODE>uppercasify</CODE>, and that programmer expected <CODE>subtleBookPlug</CODE> to be modified. Implicit type conversion for references-to-non-<CODE>const</CODE> objects, then, would allow temporary objects to be changed when programmers expected non-temporary objects to be modified. That's why the language prohibits the generation of temporaries for non-<CODE>const</CODE> reference parameters. Reference-to-<CODE>const</CODE> parameters don't suffer from this problem, because such parameters, by virtue of being <CODE>const</CODE>, can't be <NOBR>changed.<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P><A NAME="45629"></A>
<P><A NAME="dingp12"></A>
The second set of circumstances under which temporary objects are created is when a function returns an object. For instance, <CODE>operator+</CODE> must return an object that represents the sum of its operands (see <A HREF="../EC/EI23_FR.HTM#6210" TARGET="_top">Item E23</A>). Given a type <CODE>Number</CODE>, for example, <CODE>operator+</CODE> for that type would be declared like <NOBR>this:<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P>

<A NAME="45631"></A>
<UL><PRE>
const Number operator+(const Number&amp; lhs,
                       const Number&amp; rhs);
</PRE>
</UL>

<A NAME="92902"></A>
<A NAME="p101"></A><P><A NAME="dingp13"></A>
The return value of this function is a temporary, because it has no name: it's just the function's return value. You must pay to construct and destruct this object each time you call <CODE>operator+</CODE>. (For an explanation of why the return value is <CODE>const</CODE>, see <A HREF="../EC/EI21_FR.HTM#6003" TARGET="_top">Item E21</A>.)<SCRIPT>create_link(13);</SCRIPT>
</P><A NAME="45643"></A>
<P><A NAME="dingp14"></A>
As usual, you don't want to incur this cost. For this particular function, you can avoid paying by switching to a similar function, <CODE>operator+=</CODE>; <A HREF="./MI22_FR.HTM#41251" TARGET="_top">Item 22</A> tells you about this transformation. For most functions that return objects, however, switching to a different function is not an option and there is no way to avoid the construction and destruction of the return value. At least, there's no way to avoid it <I>conceptually</I>. Between concept and reality, however, lies a murky zone called <I>optimization</I>, and sometimes you can write your object-returning functions in a way that allows your compilers to optimize temporary objects out of existence. Of these optimizations, the most common and useful is the <I>return value optimization</I>, which is the subject of <A HREF="./MI20_FR.HTM#45310" TARGET="_top">Item 20</A>.<SCRIPT>create_link(14);</SCRIPT>
</P><A NAME="45512"></A>
<P><A NAME="dingp15"></A>
The bottom line is that temporary objects can be costly, so you want to eliminate them whenever you can. More important than this, however, is to train yourself to look for places where temporary objects may be created. Anytime you see a reference-to-<CODE>const</CODE> parameter, the possibility exists that a temporary will be created to bind to that parameter. Anytime you see a function returning an object, a temporary will be created (and later destroyed). Learn to look for such constructs, and your insight into the cost of "behind the scenes" compiler actions will markedly <NOBR>improve.<SCRIPT>create_link(15);</SCRIPT>
</NOBR></P>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI18_FR.HTM" TARGET="_top">Item 18: Amortize the cost of expected computations</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MI20_FR.HTM" TARGET="_top">Item 20: Facilitate the return value optimization</A></FONT></DIV>

</BODY>
</HTML>

⌨️ 快捷键说明

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