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

📄 ec2.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<!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 | Chapter 2: Memory Management</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT>var imagemax = 3; setCurrentMax(3);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/IMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/NSIMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "EC2_DIR.HTM";
var dingtext = "EC++ Mem Mgmt, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
 <!-- SectionName="EC++ Chapter Intro: Memory Management" -->
<!-- two images occurring in Chapter 2 -->
<A NAME="1865"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EC1_FR.HTM#1854" TARGET="_top">Item 4:   Prefer C++-style comments.</A>
<BR>Continue to <A HREF="#1869">Item 5: Use the same form in corresponding uses of <CODE>new</CODE> and <CODE>delete</CODE>.</A></FONT></DIV>

<P><A NAME="dingp1"></A><FONT ID="egtitle"><A NAME="p22"></A>Memory Management</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>

<A NAME="1866"></A>

<P><A NAME="dingp2"></A><A NAME="1867"></A>
Memory management concerns in C++ fall into two general camps: getting it right and making it perform efficiently. Good programmers understand that these concerns should be addressed in that order, because a program that is dazzlingly fast and astoundingly small is of little use if it doesn't behave the way it's supposed to. For most programmers, getting things right means calling memory allocation and deallocation routines correctly. Making things perform efficiently, on the other hand, often means writing custom versions of the allocation and deallocation routines. Getting things right there is even more <NOBR>important.<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>

<P><A NAME="dingp3"></A><A NAME="1868"></A>
On the correctness front, C++ inherits from C one of its biggest headaches, that of potential memory leaks. Even virtual memory, wonderful invention though it is, is finite, and not everybody has virtual memory in the first <NOBR>place.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>

<P><A NAME="dingp4"></A><A NAME="29114"></A>
In C, a memory leak arises whenever memory allocated through <CODE>malloc</CODE> is never returned through <CODE>free</CODE>. The names of the players in C++ are <CODE>new</CODE> and <CODE>delete</CODE>, but the story is much the same. However, the situation is improved somewhat by the presence of destructors, because they provide a convenient repository for calls to <CODE>delete</CODE> that all objects must make when they are destroyed. At the same time, there is more to worry about, because <CODE>new</CODE> implicitly calls constructors and <CODE>delete</CODE> implicitly calls destructors. Furthermore, there is the complication that you can define your own versions of <CODE>operator</CODE> <CODE>new</CODE> and <CODE>operator</CODE> <CODE>delete</CODE>, both inside and outside of classes. This gives rise to all kinds of opportunities to make mistakes. The following Items (as well as <A HREF="../MEC/MC2_FR.HTM#33985" TARGET="_top">Item M8</A>) should help you avoid some of the most common <NOBR>ones.<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>

 <!-- SectionName="E5: Use matching forms of new and delete." -->
<A NAME="1869"></A><DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="#1865">Memory Management</A>
<BR>Continue to <A HREF="#1885">Item 6:Use <CODE>delete</CODE> on pointer members in destructors.</A></FONT></DIV>

<P><A NAME="dingp5"></A><A NAME="p23"></A><FONT ID="eititle">Item 5: &nbsp;Use the same form in corresponding uses of <CODE>new</CODE> and <CODE>delete</CODE>.</FONT><SCRIPT>create_link(5);</SCRIPT>
</P>

<A NAME="1870"></A>
<P><A NAME="dingp6"></A>What's wrong with this <NOBR>picture?<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>

<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>
<A NAME="1874"></A>

<P><A NAME="dingp7"></A>
Everything here appears to be in order &#151; the use of <CODE>new</CODE> is matched with a use of <CODE>delete</CODE> &#151; 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(7);</SCRIPT>
</NOBR></P>
<A NAME="1875"></A>
<P><A NAME="dingp8"></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="#1894">7</A>-<A HREF="#1986">10</A> as well as <A HREF="../MEC/MC2_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> &#151; see Items <A HREF="#120851">8</A> and <A HREF="../MEC/MC2_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(8);</SCRIPT>
</NOBR></P>
<A NAME="1876"></A>
<P><A NAME="dingp9"></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(9);</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="dingp10"></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(10);</SCRIPT>
</P>
<A NAME="1884"></A>
<P><A NAME="dingp11"></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="./EC3_FR.HTM#2042" TARGET="_top">Item 11</A>.<SCRIPT>create_link(11);</SCRIPT>
</P>
<A NAME="12939"></A>
<P><A NAME="dingp12"></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(12);</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="dingp13"></A>
Because <CODE>AddressLines</CODE> is an array, this use of <CODE>new</CODE>,<SCRIPT>create_link(13);</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="dingp14"></A>
must be matched with the <i>array</i> form of <CODE>delete</CODE>:<SCRIPT>create_link(14);</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="dingp15"></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="./EC7_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&lt;string&gt;</CODE>.<SCRIPT>create_link(15);</SCRIPT>
</P>
<!-- SectionName="E6: Use delete on pointer members in destructors." -->
<A NAME="1885"></A><DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="#1869">Item 5: Use the same form in corresponding uses of <CODE>new</CODE> and <CODE>delete</CODE></A>.
<BR>Continue to <A HREF="#1894">Item 7: Be prepared for out-of-memory conditions.</A></FONT></DIV>

<P><A NAME="dingp16"></A><FONT ID="eititle">Item 6: &nbsp;Use <CODE>delete</CODE> on pointer members in destructors.</FONT><SCRIPT>create_link(16);</SCRIPT>
</P>

<A NAME="1886"></A>
<P><A NAME="dingp17"></A>
Most of the time, classes performing dynamic memory allocation will use <CODE>new</CODE> in the constructor(s) to allocate the memory and will later use <CODE>delete</CODE> in the destructor to free up the memory. This isn't too difficult to get right when you first write the class, provided, of course, that you remember to employ <CODE>delete</CODE> on <I>all</I> the members that could have been assigned memory in <I>any</I> <NOBR>constructor.<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>
<A NAME="1887"></A>
<P><A NAME="dingp18"></A>
However, the situation becomes more difficult as classes are maintained and enhanced, because the programmers making the modifications to the class may not be the ones who wrote the class in the first <A NAME="p25"></A>place. Under those conditions, it's easy to forget that adding a pointer member almost always requires each of the <NOBR>following:<SCRIPT>create_link(18);</SCRIPT>
</NOBR></p>
<UL><A NAME="1888"></A>
<A NAME="dingp19"></A><LI>Initialization of the pointer in each of the constructors. If no memory is to be allocated to the pointer in a particular constructor, the pointer should be initialized to 0 (i.e., the null pointer).<SCRIPT>create_link(19);</SCRIPT>

<A NAME="1889"></A>
<A NAME="dingp20"></A><LI>Deletion of the existing memory and assignment of new memory in the assignment operator. (See also <A HREF="./EC3_FR.HTM#2264" TARGET="_top">Item 17</A>.)<SCRIPT>create_link(20);</SCRIPT>

<A NAME="1890"></A>
<A NAME="dingp21"></A><LI>Deletion of the pointer in the destructor.<SCRIPT>create_link(21);</SCRIPT>

</UL>
<A NAME="1891"></A>
<P><A NAME="dingp22"></A>
If you forget to initialize a pointer in a constructor, or if you forget to handle it inside the assignment operator, the problem usually becomes apparent fairly quickly, so in practice those issues don't tend to plague you. Failing to delete the pointer in the destructor, however, often exhibits no obvious external symptoms. Instead, it manifests itself as a subtle memory leak, a slowly growing cancer that will eventually devour your address space and drive your program to an early demise. Because this particular problem doesn't usually call attention to itself, it's important that you keep it in mind whenever you add a pointer member to a <NOBR>class.<SCRIPT>create_link(22);</SCRIPT>
</NOBR></P>
<A NAME="1892"></A>
<P><A NAME="dingp23"></A>
Note, by the way, that deleting a null pointer is always safe (it does nothing). Thus, if you write your constructors, your assignment operators, and your other member functions such that each pointer member of the class is always either pointing to valid memory or is null, you can merrily <CODE>delete</CODE> away in the destructor without regard for whether you ever used <CODE>new</CODE> for the pointer in <NOBR>question.<SCRIPT>create_link(23);</SCRIPT>
</NOBR></P>
<A NAME="1893"></A>
<P><A NAME="dingp24"></A>
There's no reason to get fascist about this Item. For example, you certainly don't want to use <CODE>delete</CODE> on a pointer that wasn't initialized via <CODE>new</CODE>, and, except in the case of smart pointer objects (see <A HREF="../MEC/MC5_FR.HTM#61766" TARGET="_top">Item M28</A>), you almost <I>never</I> want to delete a pointer that was passed to you in the first place. In other words, your class destructor usually shouldn't be using <CODE>delete</CODE> unless your class members were the ones who used <CODE>new</CODE> in the first <NOBR>place.<SCRIPT>create_link(24);</SCRIPT>
</NOBR></P>
<A NAME="223293"></A>
<P><A NAME="dingp25"></A>
Speaking of smart pointers, one way to avoid the need to delete pointer members is to replace those members with smart pointer objects like the standard C++ Library's <CODE>auto_ptr</CODE>. To see how this can work, take a look at Items <A HREF="../MEC/MC3_FR.HTM#5292" TARGET="_top">M9</A> and <A HREF="../MEC/MC3_FR.HTM#38223" TARGET="_top">M10</A>.<SCRIPT>create_link(25);</SCRIPT>
</P>

<!-- SectionName="E7: Be prepared for out-of-memory conditions." -->
<A NAME="1894"></A><DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="#1885">Item 6: Use delete on pointer members in destructors.</A>
<BR>Continue to <A HREF="#120851">Item 8: Adhere to convention when writing operator new and operator delete.</A></FONT></DIV>

⌨️ 快捷键说明

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