📄 ei31.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>Effective C++, 2E | Item 31: Never return a reference to a local object or to a dereferenced pointer initialized by new within the function</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 = "EI31_DIR.HTM";
var dingtext = "Item E31, P";
if (self == top) {
top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E31: Avoid hazardous reference returns" -->
<A NAME="6650"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI30_FR.HTM" TARGET="_top">Item 30: Avoid member functions that return non-const pointers or references to members less accessible than themselves.</A> <BR> Continue to <A HREF="./EI32_FR.HTM" TARGET="_top">Item 32: Postpone variable definitions as long as possible.</A></FONT></DIV>
<P><A NAME="dingp1"></A><FONT ID="eititle">Item 31: Never return a reference to a local object or to a dereferenced pointer initialized by <CODE>new</CODE> within the function.</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>
<A NAME="6651"></A>
<P><A NAME="dingp2"></A>
This Item may sound complicated, but it's not. It's simple common sense. Really. Honest. <I>Trust me</I>.<SCRIPT>create_link(2);</SCRIPT>
</P>
<A NAME="6652"></A>
<P><A NAME="dingp3"></A>
Consider first the matter of returning a reference to a local object. The problem here is that local objects are just that, <I>local</I>. That means they're constructed when they're defined, and they're destructed when they go out of scope. Their scope, however, is that of the function body in which they're located. When the function returns, control leaves its scope, so the objects local to that function are automatically destructed. As a result, if you return a reference to a local object, that local object has been destructed before the caller of the function ever gets its computational hands on <NOBR>it.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>
<A NAME="6654"></A>
<P><A NAME="dingp4"></A>
This problem usually raises its ugly head when you try to improve the efficiency of a function by returning its result by reference instead of <A NAME="p132"></A>by value. The following example is the same as the one in <A HREF="./EI23_FR.HTM#6210" TARGET="_top">Item 23</A>, which pursues in detail the question of when you can return a reference and when you <NOBR>can't:<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>
<A NAME="18320"></A>
<UL><PRE>class Rational { // class for rational numbers
public:
Rational(int numerator = 0, int denominator = 1);
~Rational();
</PRE>
</UL><A NAME="18321"></A>
<UL><PRE> ...
</PRE>
</UL><A NAME="18322"></A>
<UL><PRE>private:
int n, d; // numerator and denominator
</PRE>
</UL><A NAME="18323"></A>
<UL><PRE>// notice that operator* (incorrectly) returns a reference
friend const Rational& operator*(const Rational& lhs,
const Rational& rhs);
};
</PRE>
</UL><A NAME="18335"></A>
<UL><PRE>// an incorrect implementation of operator*
inline const Rational& operator*(const Rational& lhs,
const Rational& rhs)
{
Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
return result;
}
</PRE>
</UL><A NAME="6665"></A>
<P><A NAME="dingp5"></A>
Here, the local object <CODE>result</CODE> is constructed upon entry into the body of <CODE>operator*</CODE>. However, local objects are automatically destroyed when they go out of scope. <CODE>result</CODE> will go out of scope after execution of the <CODE>return</CODE> statement, so when you write <NOBR>this,<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="6667"></A>
<UL><PRE>Rational two = 2;
</PRE>
</UL><A NAME="6668"></A>
<UL><PRE>
Rational four = two * two; // same as
// operator*(two, two)
</PRE>
</UL><A NAME="6670"></A>
<A NAME="dingp6"></A>what happens during the function call is <NOBR>this:<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>
<A NAME="6671"></A><OL TYPE="1"><A NAME="dingp7"></A><LI>The local object <CODE>result</CODE> is constructed.<SCRIPT>create_link(7);</SCRIPT>
<A NAME="6673"></A><A NAME="dingp8"></A><LI>A reference is initialized to be another name for <CODE>result</CODE>, and this reference is squirreled away as <CODE>operator*</CODE>'s return value.<SCRIPT>create_link(8);</SCRIPT>
<A NAME="6674"></A><A NAME="dingp9"></A><LI>The local object <CODE>result</CODE> is destroyed, and the space it used to occupy on the stack is made available for use by other parts of the program or by other programs.<SCRIPT>create_link(9);</SCRIPT>
<A NAME="6675"></A><A NAME="dingp10"></A><LI>The object <CODE>four</CODE> is initialized using the reference of step 2.<SCRIPT>create_link(10);</SCRIPT>
</OL></P>
<A NAME="6676"></A>
<P><A NAME="dingp11"></A>
Everything is fine until step 4, at which point there occurs, as they say in the highest of high-tech circles, "a major lossage." The reference initialized in step 2 ceased to refer to a valid object as of the end of step 3, <A NAME="p133"></A>so the outcome of the initialization of object <CODE>four</CODE> is completely <NOBR>undefined.<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P>
<A NAME="6677"></A>
<P><A NAME="dingp12"></A>
The lesson should be clear: don't return a reference to a local <NOBR>object.<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P>
<A NAME="6678"></A>
<P><A NAME="dingp13"></A>
"Okay," you say, "the problem is that the object I want to use goes out of scope too soon. I can fix that. I'll just call <CODE>new</CODE> instead of using a local object." Like <NOBR>this:<SCRIPT>create_link(13);</SCRIPT>
</NOBR></P>
</UL><A NAME="18367"></A>
<UL><PRE>// another incorrect implementation of operator*
inline const Rational& operator*(const Rational& lhs,
const Rational& rhs)
{
// create a new object on the heap
Rational *result =
new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
</PRE>
</UL><A NAME="18368"></A>
<UL><PRE> // return it
return *result;
}
</PRE>
</UL><A NAME="6681"></A>
<P><A NAME="dingp14"></A>
This approach does indeed avoid the problem of the previous example, but it introduces a new one in its place. To avoid a memory leak in your software, you know you must ensure that <CODE>delete</CODE> is applied to every pointer conjured up by <CODE>new</CODE>, but ay, there's the rub: who's to make the matching call to <CODE>delete</CODE> for this function's use of <CODE>new</CODE>?<SCRIPT>create_link(14);</SCRIPT>
</P>
<A NAME="6684"></A>
<P><A NAME="dingp15"></A>
Clearly, the <I>caller</I> of <CODE>operator*</CODE> must see to it that <CODE>delete</CODE> is applied. Clear, yes, and even easy to document, but nonetheless the cause is hopeless. There are two reasons for this pessimistic <NOBR>assessment.<SCRIPT>create_link(15);</SCRIPT>
</NOBR></P>
<A NAME="6685"></A>
<P><A NAME="dingp16"></A>
First, it's well-known that programmers, as a breed, are sloppy. That doesn't mean that you're sloppy or that I'm sloppy, but rare is the programmer who doesn't work with someone who is — shall we say? — a little on the flaky side. What are the odds that such programmers — and we all know that they exist — will remember that whenever they call <CODE>operator*</CODE>, they must <I>take the address of the result</I> and then use <CODE>delete</CODE> on it? That is, they must use <CODE>operator*</CODE> like <NOBR>this:<SCRIPT>create_link(16);</SCRIPT>
</NOBR></P>
<A NAME="6686"></A>
<UL><PRE>
const Rational& four = two * two; // get dereferenced
// pointer; store it in
// a <I>reference</I>
...
</PRE>
</UL><A NAME="6688"></A>
<UL><PRE>
delete &four; // retrieve pointer
// and delete it
</PRE>
</UL><A NAME="6689"></A>
<P><A NAME="dingp17"></A>
The odds are vanishingly small. Remember, if only a <I>single caller</I> of <CODE>operator*</CODE> fails to follow the rules, you have a memory <NOBR>leak.<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>
<A NAME="6690"></A>
<P><A NAME="dingp18"></A>
<A NAME="p134"></A>Returning dereferenced pointers has a second, more serious, problem, because it persists even in the presence of the most conscientious of programmers. Often, the result of <CODE>operator*</CODE> is a temporary intermediate value, an object that exists only for the purposes of evaluating a larger expression. For <NOBR>example:<SCRIPT>create_link(18);</SCRIPT>
</NOBR></P>
<A NAME="6692"></A>
<UL><PRE>Rational one(1), two(2), three(3), four(4);
Rational product;
</PRE>
</UL><A NAME="6693"></A>
<UL><PRE>product = one * two * three * four;
</PRE>
</UL><A NAME="6694"></A>
<P><A NAME="dingp19"></A>
Evaluation of the expression to be assigned to <CODE>product</CODE> requires three separate calls to <CODE>operator*</CODE>, a fact that becomes more evident when you rewrite the expression in its equivalent functional <NOBR>form:<SCRIPT>create_link(19);</SCRIPT>
</NOBR></P>
<A NAME="6695"></A>
<UL><PRE>product = operator*(operator*(operator*(one, two), three), four);
</PRE>
</UL><A NAME="6696"></A>
<P><A NAME="dingp20"></A>
You know that each of the calls to <CODE>operator*</CODE> returns an object that needs to be deleted, but there is no possibility of applying <CODE>delete</CODE>, because none of the returned objects has been saved <NOBR>anywhere.<SCRIPT>create_link(20);</SCRIPT>
</NOBR></P>
<A NAME="6697"></A>
<P><A NAME="dingp21"></A>
The only solution to this difficulty is to ask clients to code like <NOBR>this:<SCRIPT>create_link(21);</SCRIPT>
</NOBR></P>
<A NAME="6698"></A>
<UL><PRE>const Rational& temp1 = one * two;
const Rational& temp2 = temp1 * three;
const Rational& temp3 = temp2 * four;
</PRE>
</UL><A NAME="6699"></A>
<UL><PRE>delete &temp1;
delete &temp2;
delete &temp3;
</PRE>
</UL><A NAME="6700"></A>
<P><A NAME="dingp22"></A>
Do that, and the best you can hope for is that people will ignore you. More realistically, you'd be skinned alive, or possibly sentenced to ten years hard labor writing microcode for waffle irons and toaster <NOBR>ovens.<SCRIPT>create_link(22);</SCRIPT>
</NOBR></P>
<A NAME="6701"></A>
<P><A NAME="dingp23"></A>
Learn your lesson now, then: writing a function that returns a dereferenced pointer is a memory leak just waiting to <NOBR>happen.<SCRIPT>create_link(23);</SCRIPT>
</NOBR></P>
<A NAME="25935"></A>
<P><A NAME="dingp24"></A>
By the way, if you think you've come up with a way to avoid the undefined behavior inherent in returning a reference to a local object and the memory leak haunting the return of a reference to a heap-allocated object, turn to <A HREF="./EI23_FR.HTM#6210" TARGET="_top">Item 23</A> and read why returning a reference to a local <CODE>static</CODE> object also fails to work correctly. It may save you the trouble of seeking medical care for the arm you're likely to strain trying to pat yourself on the <NOBR>back.<SCRIPT>create_link(24);</SCRIPT>
</NOBR></P>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI30_FR.HTM" TARGET="_top">Item 30: Avoid member functions that return non-const pointers or references to members less accessible than themselves.</A> <BR> Continue to <A HREF="./EI32_FR.HTM" TARGET="_top">Item 32: Postpone variable definitions as long as possible.</A></FONT></DIV>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -