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

📄 mi20.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 20: Facilitate the return value optimization</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 = "MI20_DIR.HTM";
var dingtext = "Item M20, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="M20: Facilitate the return value optimization" -->
<A NAME="45310"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI19_FR.HTM" TARGET="_top">Item 19: Understand the origin of temporary objects</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MI21_FR.HTM" TARGET="_top">Item 21: Overload to avoid implicit type conversions</A></FONT></DIV>


<P><A NAME="dingp1"></A><font ID="mititle">Item 20: &nbsp;Facilitate the return value optimization.</font><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="72150"></A><A NAME="50166"></A>
<P><A NAME="dingp2"></A>
A function that returns an object is frustrating to efficiency aficionados, because the by-value return, including the constructor and destructor calls it implies (see <A HREF="./MI19_FR.HTM#41177" TARGET="_top">Item 19</A>), cannot be eliminated. The problem is simple: a function either has to return an object in order to offer correct behavior or it doesn't. If it does, there's no way to get rid of the object being returned. <NOBR>Period.<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P><A NAME="50167"></A>
<P><A NAME="dingp3"></A>
Consider the <CODE>operator*</CODE> function for rational <NOBR>numbers:<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>

<A NAME="50176"></A>
<UL><PRE><A NAME="p102"></A>class Rational {
public:
  Rational(int numerator = 0, int denominator = 1);
  ...
  int numerator() const;
  int denominator() const;
};
<A NAME="50201"></A>
// For an explanation of why the return value is const,
// see <A HREF="./MI6_FR.HTM#5262" TARGET="_top">Item 6</A>
const Rational operator*(const Rational&amp; lhs,
                         const Rational&amp; rhs);
</PRE>
</UL>
<A NAME="50202"></A>
<P><A NAME="dingp4"></A>
Without even looking at the code for <CODE>operator*</CODE>, we know it must return an object, because it returns the product of two arbitrary numbers. These are <I>arbitrary</I> numbers. How can <CODE>operator*</CODE> possibly avoid creating a new object to hold their product?   It can't, so it must create a new object and return it. C++ programmers have nevertheless expended Herculean efforts in a search for the legendary elimination of the by-value return (see Items <a href="../EC/EI23_FR.HTM#6210" TARGET="_top">E23</A> and <a href="../EC/EI31_FR.HTM#6650" TARGET="_top">E31</A>).<SCRIPT>create_link(4);</SCRIPT>
</P><A NAME="50579"></A>
<P><A NAME="dingp5"></A>
Sometimes people return pointers, which leads to this syntactic <NOBR>travesty:<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="50211"></A>
<UL><PRE>// an unreasonable way to avoid returning an object
const Rational * operator*(const Rational&amp; lhs,
                           const Rational&amp; rhs);
<A NAME="50209"></A>
Rational a = 10;
Rational b(1, 2);
<A NAME="50214"></A>
Rational c = *(a * b);                       // Does this look "natural"
                                             // to you?
</PRE>
</UL>
<A NAME="50215"></A>
<P><A NAME="dingp6"></A>
It also raises a question. Should the caller delete the pointer returned by the function? The answer is usually yes, and that usually leads to resource <NOBR>leaks.<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P><A NAME="7799"></A>
<P><A NAME="dingp7"></A>
Other developers return references. That yields an acceptable <NOBR>syntax,<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P>

<A NAME="7800"></A>
<UL><PRE>// a dangerous (and incorrect) way to avoid returning
// an object
const Rational&amp; operator*(const Rational&amp; lhs,
                          const Rational&amp; rhs);
<A NAME="50221"></A>
Rational a = 10;
Rational b(1, 2);
<A NAME="50222"></A>
Rational c = a * b;                          // looks perfectly reasonable
</PRE>
</UL>
<A NAME="45736"></A>
<P><A NAME="dingp8"></A>but such functions can't be implemented in a way that behaves correctly. A common attempt looks like <NOBR>this:<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>
<A NAME="50237"></A>
<UL><PRE><A NAME="p103"></A>// another dangerous (and incorrect) way to avoid
// returning an object
const Rational&amp; operator*(const Rational&amp; lhs,
                          const Rational&amp; rhs)
{
  Rational result(lhs.numerator() * rhs.numerator(),
                  lhs.denominator() * rhs.denominator());
  return result;
}
</PRE>
</UL>
<A NAME="50249"></A>
<P><A NAME="dingp9"></A>
This function returns a reference to an object that no longer exists. In particular, it returns a reference to the local object <CODE>result</CODE>, but <CODE>result</CODE> is automatically destroyed when <CODE>operator*</CODE> is exited. Returning a reference to an object that's been destroyed is hardly <NOBR>useful.<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P><A NAME="50302"></A>
<P><A NAME="dingp10"></A>
Trust me on this: some functions (<CODE>operator*</CODE> among them) just have to return objects. That's the way it is. Don't fight it. You can't <NOBR>win.<SCRIPT>create_link(10);</SCRIPT>
</NOBR></P><A NAME="50307"></A>
<P><A NAME="dingp11"></A>
That is, you can't win in your effort to eliminate by-value returns from functions that require them. But that's the wrong war to wage. From an efficiency point of view, you shouldn't care that a function returns an object, you should only care about the <i>cost</i> of that object. What you need to do is channel your efforts into finding a way to reduce the cost of returned objects, not to eliminate the objects themselves (which we now recognize is a futile quest). If no cost is associated with such objects, who cares how many get <NOBR>created?<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P><A NAME="50308"></A>
<P><A NAME="dingp12"></A>
It is frequently possible to write functions that return objects in such a way that compilers can eliminate the cost of the temporaries. The trick is to return <I>constructor arguments</I> instead of objects, and you can do it like <NOBR>this:<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P>

<A NAME="50316"></A>
<UL><PRE>// an efficient and correct way to implement a
// function that returns an object
const Rational operator*(const Rational&amp; lhs,
                         const Rational&amp; rhs)
{
  return Rational(lhs.numerator() * rhs.numerator(),
                  lhs.denominator() * rhs.denominator());
}
</PRE>
</UL><A NAME="79739"></A>
<P><A NAME="dingp13"></A>
Look closely at the expression being returned. It looks like you're calling a <CODE>Rational</CODE> constructor, and in fact you are. You're creating a temporary <CODE>Rational</CODE> object through this <NOBR>expression,<SCRIPT>create_link(13);</SCRIPT>
</NOBR></P>

<A NAME="50328"></A>
<UL><PRE>Rational(lhs.numerator() * rhs.numerator(),
         lhs.denominator() * rhs.denominator());
</PRE>
</UL>
<A NAME="50337"></A>

<P><A NAME="dingp14"></A>and it is this temporary object the function is copying for its return <NOBR>value.<SCRIPT>create_link(14);</SCRIPT>
</NOBR></P>

<A NAME="50380"></A>
<A NAME="p104"></A>
<P><A NAME="dingp15"></A>
This business of returning constructor arguments instead of local objects doesn't appear to have bought you a lot, because you still have to pay for the construction and destruction of the temporary created inside the function, and you still have to pay for the construction and destruction of the object the function returns. But you have gained something. The rules for C++ allow compilers to optimize temporary objects out of existence. As a result, if you call <CODE>operator*</CODE> in a context like <NOBR>this,<SCRIPT>create_link(15);</SCRIPT>
</NOBR></P>

<A NAME="50343"></A>
<UL><PRE>Rational a = 10;
Rational b(1, 2);
<A NAME="50344"></A>
Rational c = a * b;                          // operator* is called here
</PRE>
</UL><A NAME="50341"></A>

<P><A NAME="dingp16"></A>your compilers are allowed to eliminate both the temporary inside <CODE>operator*</CODE> <i>and</i> the temporary returned by <CODE>operator*</CODE>. They can construct the object defined by the <CODE>return</CODE> expression <I>inside the memory allotted for the object <CODE>c</CODE></I>. If your compilers do this, the total cost of temporary objects as a result of your calling <CODE>operator*</CODE> is zero: no temporaries are created. Instead, you pay for only one constructor call &#151; the one to create <CODE>c</CODE>. Furthermore, you can't do any better than this, because <CODE>c</CODE> is a named object, and named objects can't be eliminated (see also <A HREF="./MI22_FR.HTM#41251" TARGET="_top">Item 22</A>).<a href="#10118"><sup>7</sup></A> You can, however, eliminate the overhead of the call to <CODE>operator*</CODE> by declaring that function <CODE>inline</CODE> (but first see <A HREF="../EC/EI33_FR.HTM#6729" TARGET="_top">Item E33</A>):<SCRIPT>create_link(16);</SCRIPT>
</P>

<A NAME="73091"></A>
<UL><PRE>// the most efficient way to write a function returning
// an object
inline const Rational operator*(const Rational&amp; lhs,
                                const Rational&amp; rhs)
{
  return Rational(lhs.numerator() * rhs.numerator(),
                  lhs.denominator() * rhs.denominator());
}
</PRE>
</UL>
<A NAME="50354"></A>
<P><A NAME="dingp17"></A>
"Yeah, yeah," you mutter, "optimization, schmoptimization. Who cares what compilers <I>can</I> do? I want to know what they <I>do</I> do. Does any of this nonsense work with real compilers?" It does. This particular optimization &#151; eliminating a local temporary by using a function's return location (and possibly replacing that with an object at the function's call site) &#151; is both well-known and commonly implemented. It even has a name: the <I>return value optimization</I>. In fact, the existence of a name for this optimization may explain why it's so widely available. Programmers looking for a C++ compiler can ask vendors whether the return value optimization is implemented. If one vendor says yes and another says "The what?," the first vendor has a notable competitive advantage. Ah, capitalism. Sometimes you just gotta love <NOBR>it.<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>

<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./MI19_FR.HTM" TARGET="_top">Item 19: Understand the origin of temporary objects</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./MI21_FR.HTM" TARGET="_top">Item 21: Overload to avoid implicit type conversions</A></FONT></DIV>

<HR>
<A NAME="dingp18"></A>
<sup>7</sup><A NAME="10118"> </A>In July 1996, the <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>&deg;</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=committee" onMouseOver="self.status='ISO/ANSI Standardization Committee Home Page'; return true" onMouseOut="self.status=self.defaultStatus" target="_top">ISO/ANSI</NOBR> standardization committee</A> declared that both named and unnamed objects may be optimized away via the return value optimization, so both versions of <CODE>operator*</CODE> above may now yield the same (optimized) object code.<SCRIPT>create_link(18);</SCRIPT>
<BR>
<A HREF="#50341">Return</A>

</BODY>
</HTML>

⌨️ 快捷键说明

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