📄 ei5.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 5: Use the same form in corresponding uses of new and delete</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 = "EI5_DIR.HTM";
var dingtext = "Item E5, P";
if (self == top) {
top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E5: Use matching forms of new and delete" -->
<A NAME="1869"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="EMEM_FR.HTM" TARGET="_top">Memory Management</A> <BR> Continue to <A HREF="EI6_FR.HTM" TARGET="_top">Item 6: Use delete on pointer members in destructors.</A></DIV></FONT>
<P><A NAME="dingp1"></A><A NAME="p23"></A><FONT ID="eititle">Item 5: Use the same form in corresponding uses of <CODE>new</CODE> and <CODE>delete</CODE>.</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>
<A NAME="1870"></A>
<P><A NAME="dingp2"></A>
What's wrong with this picture?<SCRIPT>create_link(2);</SCRIPT>
<A NAME="1871"></A>
<UL><PRE>string *stringArray = new string[100];
</PRE>
</UL><A NAME="1872"></A>
<UL><PRE>...
</PRE>
</UL><A NAME="1873"></A>
<UL><PRE>delete stringArray;
</PRE>
</UL></P>
<A NAME="1874"></A>
<P><A NAME="dingp3"></A>
Everything here appears to be in order — the use of <CODE>new</CODE> is matched with a use of <CODE>delete</CODE> — but something is still quite wrong: your program's behavior is undefined. At the very least, 99 of the 100 <CODE>string</CODE> objects pointed to by <CODE>stringArray</CODE> are unlikely to be properly destroyed, because their destructors will probably never be <NOBR>called.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>
<A NAME="1875"></A>
<P><A NAME="dingp4"></A>
When you use <CODE>new</CODE>, two things happen. First, memory is allocated (via the function <CODE>operator</CODE> <CODE>new</CODE>, about which I'll have more to say in Items <A HREF="./EI7_FR.HTM#1894" TARGET="_top">7</A>-<A HREF="./EI10_FR.HTM#1986" TARGET="_top">10</A> as well as <A HREF="../MEC/MI8_FR.HTM#33985" TARGET="_top">Item M8</A>). Second, one or more constructors are called for that memory. When you use <CODE>delete</CODE>, two other things happen: one or more destructors are called for the memory, then the memory is deallocated (via the function <CODE>operator</CODE> <CODE>delete</CODE> — see Items <A HREF="./EI8_FR.HTM#120851" TARGET="_top">8</A> and <A HREF="../MEC/MI8_FR.HTM#33985" TARGET="_top">M8</A>). The big question for <CODE>delete</CODE> is this: <I>how many</I> objects reside in the memory being deleted? The answer to that determines how many destructors must be <NOBR>called.<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>
<A NAME="1876"></A>
<P><A NAME="dingp5"></A>
Actually, the question is simpler: does the pointer being deleted point to a single object or to an array of objects? The only way for <CODE>delete</CODE> to know is for you to tell it. If you don't use brackets in your use of <CODE>delete</CODE>, <CODE>delete</CODE> assumes a single object is pointed to. Otherwise, it assumes that an array is pointed <NOBR>to:<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="1877"></A>
<UL><PRE>
string *stringPtr1 = new string;
</PRE>
</UL><A NAME="1878"></A>
<UL><PRE>
string *stringPtr2 = new string[100];
</PRE>
</UL><A NAME="1879"></A>
<UL><PRE>...
</PRE>
</UL><A NAME="1880"></A>
<UL><PRE>
delete stringPtr1; // delete an object</PRE>
</UL><A NAME="1881"></A>
<UL><PRE>
delete [] stringPtr2; // delete an array of
// objects
</PRE>
</UL><A NAME="13160"></A>
<P><A NAME="dingp6"></A>
What would happen if you used the "<CODE>[]</CODE>" form on <CODE>stringPtr1</CODE>? The result is undefined. What would happen if you didn't use the "<CODE>[]</CODE>" form on <CODE>stringPtr2</CODE>? Well, that's undefined too. Furthermore, it's undefined even for built-in types like <CODE>int</CODE>s, even though such types lack destructors. The rule, then, is simple: if you use <CODE>[]</CODE> when you call <CODE>new</CODE>, you must use <CODE>[]</CODE> when you call <CODE>delete</CODE>. If you don't use <CODE>[]</CODE> when you call <CODE>new</CODE>, don't use <CODE>[]</CODE> when you call <CODE>delete</CODE>.<SCRIPT>create_link(6);</SCRIPT>
</P>
<A NAME="1884"></A>
<P><A NAME="dingp7"></A>
<A NAME="p24"></A>This is a particularly important rule to bear in mind when you are writing a class containing a pointer data member and also offering multiple constructors, because then you've got to be careful to use the <I>same form</I> of <CODE>new</CODE> in all the constructors to initialize the pointer member. If you don't, how will you know what form of <CODE>delete</CODE> to use in your destructor? For a further examination of this issue, see <A HREF="./EI11_FR.HTM#2042" TARGET="_top">Item 11</A>.<SCRIPT>create_link(7);</SCRIPT>
</P>
<A NAME="12939"></A>
<P><A NAME="dingp8"></A>
This rule is also important for the <CODE>typedef</CODE>-inclined, because it means that a <CODE>typedef</CODE>'s author must document which form of <CODE>delete</CODE> should be employed when <CODE>new</CODE> is used to conjure up objects of the <CODE>typedef</CODE> type. For example, consider this <CODE>typedef</CODE>:<SCRIPT>create_link(8);</SCRIPT>
</P>
<A NAME="12940"></A>
<UL><PRE>
typedef string AddressLines[4]; // a person's address
// has 4 lines, each of
// which is a string
</PRE>
</UL><A NAME="12956"></A>
<P><A NAME="dingp9"></A>
Because <CODE>AddressLines</CODE> is an array, this use of <CODE>new</CODE>,<SCRIPT>create_link(9);</SCRIPT>
</P>
<A NAME="12957"></A>
<UL><PRE>
string *pal = new AddressLines; // note that "new
// AddressLines" returns
// a string*, just like
// "new string[4]" would
</PRE>
</UL><A NAME="12958"></A>
<P><A NAME="dingp10"></A>
must be matched with the <i>array</i> form of <CODE>delete</CODE>:<SCRIPT>create_link(10);</SCRIPT>
</P>
<A NAME="12959"></A>
<UL><PRE>
delete pal; // undefined!
</PRE>
</UL><A NAME="12960"></A>
<UL><PRE>
delete [] pal; // fine
</PRE>
</UL><A NAME="12978"></A>
<P><A NAME="dingp11"></A>
To avoid such confusion, you're probably best off abstaining from <CODE>typedef</CODE>s for array types. That should be easy, however, because the standard C++ library (see <A HREF="./EI49_FR.HTM#8392" TARGET="_top">Item 49</A>) includes <CODE>string</CODE> and <CODE>vector</CODE> templates that reduce the need for built-in arrays to nearly zero. Here, for example, <CODE>AddressLines</CODE> could be defined to be a <CODE>vector</CODE> of <CODE>string</CODE>s. That is, <CODE>AddressLines</CODE> could be of type <CODE>vector<string></CODE>.<SCRIPT>create_link(11);</SCRIPT>
</P>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="EMEM_FR.HTM" TARGET="_top">Memory Management</A> <BR> Continue to <A HREF="EI6_FR.HTM" TARGET="_top">Item 6: Use delete on pointer members in destructors.</A></DIV></FONT>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -