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

📄 ei23.htm

📁 高效c++编程
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="EN">
<HEAD>
<title>Effective C++, 2E | Item 23: Don't try to return a reference when you must return an object</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 LANGUAGE="Javascript">
var dingbase = "EI23_DIR.HTM";
var dingtext = "Item E23, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E23: Return objects when you must" -->
<A NAME="6210"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI22_FR.HTM" TARGET="_top">Item 22: Prefer pass-by-reference to pass-by-value.</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./EI24_FR.HTM" TARGET="_top">Item 24: Choose carefully between function overloading and parameter defaulting.</A></FONT></DIV>

<P><A NAME="dingp1"></A><FONT ID="eititle">Item 23: &nbsp;Don't try to return a reference when you must return an object.</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="6212"></A>
<P><A NAME="dingp2"></A>
It is said that Albert Einstein once offered this advice: make things as simple as possible, but no simpler. The C++ analogue might well be to make things as efficient as possible, but no more <NOBR>efficient.<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>
<A NAME="6213"></A>
<P><A NAME="dingp3"></A>
Once programmers grasp the efficiency implications of pass-by-value for objects (see <A HREF="./EI22_FR.HTM#6133" TARGET="_top">Item 22</A>), they become crusaders, determined to root out the evil of pass-by-value wherever it may hide. Unrelenting in their pursuit of pass-by-reference purity, they invariably make a fatal mistake: they start to pass references to objects that don't exist. This is not a good <NOBR>thing.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>
<A NAME="6217"></A>
<P><A NAME="dingp4"></A>
Consider a class for representing rational numbers, including a friend function (see <A HREF="./EI19_FR.HTM#5887" TARGET="_top">Item 19</A>) for multiplying two rationals <NOBR>together:<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>
<A NAME="16830"></A>
<UL><PRE>class Rational {
public:
  Rational(int numerator = 0, int denominator = 1);
</PRE>
</UL><A NAME="16831"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="16832"></A>
<UL><PRE>private:
  int n, d;              // numerator and denominator
</PRE>
</UL><A NAME="17983"></A>
<UL><PRE><A NAME="p102"></A>friend
  const Rational                      // see <A HREF="./EI21_FR.HTM#6003" TARGET="_top">Item 21</A> for why
    operator*(const Rational&amp; lhs,    // the return value is
              const Rational&amp; rhs)    // const
};
</PRE>
</UL><A NAME="6223"></A>
<UL><PRE>inline const Rational operator*(const Rational&amp; lhs,
                                const Rational&amp; rhs)
{
  return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
}
</PRE>
</UL><A NAME="6224"></A>
<P><A NAME="dingp5"></A>
Clearly, this version of <CODE>operator*</CODE> is returning its result object by value, and you'd be shirking your professional duties if you failed to worry about the cost of that object's construction and destruction. Another thing that's clear is that you're cheap and you don't want to pay for such a temporary object (see <A HREF="../MEC/MI19_FR.HTM#41177" TARGET="_top">Item M19</A>) if you don't have to. So the question is this: do you have to <NOBR>pay?<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="6226"></A>
<P><A NAME="dingp6"></A>
Well, you don't have to if you can return a reference instead. But remember that a reference is just a <I>name</I>, a name for some <I>existing</I> object. Whenever you see the declaration for a reference, you should immediately ask yourself what it is another name for, because it must be another name for <I>something</I> (see <A HREF="../MEC/MI1_FR.HTM#11029" TARGET="_top">Item M1</A>). In the case of <CODE>operator*</CODE>, if the function is to return a reference, it must return a reference to some other <CODE>Rational</CODE> object that already exists and that contains the product of the two objects that are to be multiplied <NOBR>together.<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>
<A NAME="6227"></A>
<P><A NAME="dingp7"></A>
There is certainly no reason to expect that such an object exists prior to the call to <CODE>operator*</CODE>. That is, if you <NOBR>have<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P>
<A NAME="16865"></A>
<UL><PRE>Rational a(1, 2);                // a = 1/2
Rational b(3, 5);                // b = 3/5
Rational c = a * b;              // c should be 3/10
</PRE>
</UL><A NAME="16866"></A>
<P><A NAME="dingp8"></A>
it seems unreasonable to expect that there already exists a rational number with the value three-tenths. No, if <CODE>operator*</CODE> is to return a reference to such a number, it must create that number object <NOBR>itself.<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>
<A NAME="6230"></A>
<P><A NAME="dingp9"></A>
A function can create a new object in only two ways: on the stack or on the heap. Creation on the stack is accomplished by defining a local variable. Using that strategy, you might try to write your <CODE>operator*</CODE> as <NOBR>follows:<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<A NAME="6231"></A>
<UL><PRE>// the first wrong way to write this function
inline const Rational&amp; operator*(const Rational&amp; lhs,
                                 const Rational&amp; rhs)
{
  Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
  return result;
}
</PRE>
</UL><A NAME="6232"></A>
<P><A NAME="dingp10"></A>
<A NAME="p103"></A>You can reject this approach out of hand, because your goal was to avoid a constructor call, and <CODE>result</CODE> will have to be constructed just like any other object. In addition, this function has a more serious problem in that it returns a reference to a local object, an error that is discussed in depth in <A HREF="./EI31_FR.HTM#6650" TARGET="_top">Item 31</A>.<SCRIPT>create_link(10);</SCRIPT>
</P>
<A NAME="6236"></A>
<P><A NAME="dingp11"></A>
That leaves you with the possibility of constructing an object on the heap and then returning a reference to it. Heap-based objects come into being through the use of <CODE>new</CODE>. This is how you might write <CODE>operator*</CODE> in that <NOBR>case:<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P>
<A NAME="6237"></A>
<UL><PRE>// the second wrong way to write this function
inline const Rational&amp; operator*(const Rational&amp; lhs,
                                 const Rational&amp; rhs)
{
  Rational *result =
    new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
  return *result;
}
</PRE>
</UL><A NAME="6238"></A>
<P><A NAME="dingp12"></A>
Well, you <I>still</I> have to pay for a constructor call, because the memory allocated by <CODE>new</CODE> is initialized by calling an appropriate constructor (see Items <A HREF="./EI5_FR.HTM#1869" TARGET="_top">5</A> and <A HREF="../MEC/MI8_FR.HTM#33985" TARGET="_top">M8</A>), but now you have a different problem: who will apply <CODE>delete</CODE> to the object that was conjured up by your use of <CODE>new</CODE>?<SCRIPT>create_link(12);</SCRIPT>
</P>

⌨️ 快捷键说明

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