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

📄 ei10.htm

📁 一个非常适合初学者入门的有关c++的文档
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<!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 10: Write operator delete if you write operator new</TITLE>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>

<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/IMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/NSIMGDOC.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">var imagemax = 3; setCurrentMax(3);</SCRIPT>
<SCRIPT LANGUAGE="Javascript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="Javascript">
var dingbase = "EI10_DIR.HTM";
var dingtext = "Item E10, P";
if (self == top) {
 top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>

</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" ONLOAD="setResize()">
<!-- SectionName="E10: Write delete if you write new" -->
<A NAME="1986"></A>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EI9_FR.HTM" TARGET="_top">Item 9: Avoid hiding the "normal" form of new.</A> &nbsp;&nbsp;<BR>&nbsp;&nbsp;Continue to <A HREF="./ECTOR_FR.HTM" TARGET="_top">Constructors, Destructors, and Assignment Operators</A></FONT></DIV>

<P><A NAME="dingp1"></A><A NAME="1987"></A><FONT ID="eititle">Item 10: &nbsp;Write <CODE>operator</CODE> <CODE>delete</CODE> if you write <CODE>operator</CODE> <CODE>new</CODE>.</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>

<p><A NAME="dingp2"></A>
Let's step back for a moment and return to fundamentals. Why would anybody want to write their own version of <CODE>operator</CODE> <CODE>new</CODE> or <CODE>operator</CODE> <CODE>delete</CODE> in the first <NOBR>place?<SCRIPT>create_link(2);</SCRIPT>
</NOBR></P>
<A NAME="1988"></A>
<P><A NAME="dingp3"></A>
More often than not, the answer is efficiency. The default versions of <CODE>operator</CODE> <CODE>new</CODE> and <CODE>operator</CODE> <CODE>delete</CODE> are perfectly adequate for general-purpose use, but their flexibility inevitably leaves room for improvements in their performance in a more circumscribed context. This is especially true for applications that dynamically allocate a large number of small <NOBR>objects.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>
<A NAME="1989"></A>
<P><A NAME="dingp4"></A>
As an example, consider a class for representing airplanes, where the <CODE>Airplane</CODE> class contains only a pointer to the actual representation for airplane objects (a technique discussed in <A HREF="./EI34_FR.HTM#6793" TARGET="_top">Item 34</A>):<SCRIPT>create_link(4);</SCRIPT>
</P>
<A NAME="28421"></A>
<UL><PRE>class AirplaneRep { ... };      // representation for an
                                // Airplane object
class Airplane {
public:
  ...
private:
  AirplaneRep *rep;             // pointer to representation
};
</PRE>
</UL><A NAME="1994"></A>
<P><A NAME="dingp5"></A>
<A NAME="p40"></A>An <CODE>Airplane</CODE> object is not very big; it contains but a single pointer. (As explained in Items <A HREF="./EI14_FR.HTM#223029" TARGET="_top">14</A> and <A HREF="../MEC/MI24_FR.HTM#41284" TARGET="_top">M24</A>, it may implicitly contain a second pointer if the <CODE>Airplane</CODE> class declares virtual functions.) When you allocate an <CODE>Airplane</CODE> object by calling <CODE>operator</CODE> <CODE>new</CODE>, however, you probably get back more memory than is needed to store this pointer (or pair of pointers). The reason for this seemingly wayward behavior has to do with the need for <CODE>operator</CODE> <CODE>new</CODE> and <CODE>operator</CODE> <CODE>delete</CODE> to communicate with one <NOBR>another.<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<A NAME="1995"></A>
<P><A NAME="dingp6"></A>
Because the default version of <CODE>operator</CODE> <CODE>new</CODE> is a general-purpose allocator, it must be prepared to allocate blocks of any size. Similarly, the default version of <CODE>operator</CODE> <CODE>delete</CODE> must be prepared to deallocate blocks of whatever size <CODE>operator</CODE> <CODE>new</CODE> allocated. For <CODE>operator</CODE> <CODE>delete</CODE> to know how much memory to deallocate, it must have some way of knowing how much memory <CODE>operator</CODE> <CODE>new</CODE> allocated in the first place. A common way for <CODE>operator</CODE> <CODE>new</CODE> to tell <CODE>operator</CODE> <CODE>delete</CODE> how much memory it allocated is by prepending to the memory it returns some additional data that specifies the size of the allocated block. That is, when you say <NOBR>this,<SCRIPT>create_link(6);</SCRIPT>
</NOBR></P>
<A NAME="1996"></A>
<UL><PRE>Airplane *pa = new Airplane;
</PRE>
</UL><A NAME="1997"></A>
<P><A NAME="dingp7"></A>
you don't necessarily get back a block of memory that looks like <NOBR>this:<SCRIPT>create_link(7);</SCRIPT>
</NOBR></p>

<SPAN ID="Image1of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040A1.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040A2.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040A3.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040A4.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040A5.GIF" BORDER=0></SPAN>
<SPAN ID="Image1of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040A5.GIF" BORDER=0></SPAN>

<A NAME="214466"></A>
<P><A NAME="dingp8"></A>
Instead, you often get back a block of memory that looks more like <NOBR>this:<SCRIPT>create_link(8);</SCRIPT>
</NOBR></P>

<SPAN ID="Image2of1" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040B1.GIF" BORDER=0></SPAN>
<SPAN ID="Image2of2" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040B2.GIF" BORDER=0></SPAN>
<SPAN ID="Image2of3" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040B3.GIF" BORDER=0></SPAN>
<SPAN ID="Image2of4" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040B4.GIF" BORDER=0></SPAN>
<SPAN ID="Image2of5" STYLE="position: absolute; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040B5.GIF" BORDER=0></SPAN>
<SPAN ID="Image2of6" STYLE="position: relative; z-index:1; visibility: hidden"><IMG SRC="./IMAGES/GRAPHICS/DIAGRAMS/I_040B5.GIF" BORDER=0></SPAN>

<A NAME="13986"></A>
<P><A NAME="dingp9"></A>
For small objects like those of class <CODE>Airplane</CODE>, this additional bookkeeping data can more than double the amount of memory needed for each dynamically allocated object (especially if the class contains no virtual <NOBR>functions).<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<A NAME="14003"></A>
<P><A NAME="dingp10"></A>
If you're developing software for an environment in which memory is precious, you may not be able to afford this kind of spendthrift allocation. By writing your own <CODE>operator</CODE> <CODE>new</CODE> for the <CODE>Airplane</CODE> class, you can take advantage of the fact that all <CODE>Airplane</CODE> objects are the same <A NAME="p41"></A>size, so there isn't any need for bookkeeping information to be kept with each allocated <NOBR>block.<SCRIPT>create_link(10);</SCRIPT>
</NOBR></P>
<A NAME="14079"></A>
<P><A NAME="dingp11"></A>
One way to implement your class-specific <CODE>operator</CODE> <CODE>new</CODE> is to ask the default <CODE>operator</CODE> <CODE>new</CODE> for big blocks of raw memory, each block of sufficient size to hold a large number of <CODE>Airplane</CODE> objects. The memory chunks for <CODE>Airplane</CODE> objects themselves will be taken from these big blocks. Currently unused chunks will be organized into a linked list &#151; the <I>free</I> list &#151; of chunks that are available for future <CODE>Airplane</CODE> use. This may make it sound like you'll have to pay for the overhead of a <CODE>next</CODE> field in every object (to support the list), but you won't: the space for the <CODE>rep</CODE> field (which is necessary only for memory chunks in use as <CODE>Airplane</CODE> objects) will also serve as the place to store the <CODE>next</CODE> pointer (because that pointer is needed only for chunks of memory <I>not</I> in use as <CODE>Airplane</CODE> objects). You'll arrange for this job-sharing in the usual fashion: you'll use a <CODE>union</CODE>.<SCRIPT>create_link(11);</SCRIPT>
</P>
<A NAME="2000"></A>
<P><A NAME="dingp12"></A>
To turn this design into reality, you have to modify the definition of <CODE>Airplane</CODE> to support custom memory management. You do it as <NOBR>follows:<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P>
<A NAME="14158"></A>
<UL><PRE>
class Airplane {           // modified class &#151; now supports
public:                    // custom memory management
</PRE>
</UL><A NAME="14165"></A>
<UL><PRE>  static void * operator new(size_t size);
</PRE>
</UL><A NAME="14066"></A>
<UL><PRE>  ...
</PRE>
</UL><A NAME="14160"></A>
<UL><PRE>private:
  union {
    AirplaneRep *rep;      // for objects in use
    Airplane *next;        // for objects on free list
  };
</PRE>
</UL><A NAME="14067"></A>
<UL><PRE>
  // this class-specific constant (see <A HREF="./EI1_FR.HTM#1790" TARGET="_top">Item 1</A>) specifies how
  // many Airplane objects fit into a big memory block;
  // it's initialized below
  static const int BLOCK_SIZE;
</PRE>
</UL><A NAME="14068"></A>
<UL><PRE>  static Airplane *headOfFreeList;
</PRE>
</UL><A NAME="14071"></A>
<UL><PRE>};
</PRE>
</UL><A NAME="2005"></A>
<P><A NAME="dingp13"></A>
Here you've added the declarations for <CODE>operator</CODE> <CODE>new</CODE>, the union that allows the <CODE>rep</CODE> and <CODE>next</CODE> fields to occupy the same memory, a class-specific constant for specifying how big each allocated block should be, and a static pointer to keep track of the head of the free list. It's important to use a static member for this last task, because there's one free list for the entire <I>class</I>, not one free list for each <CODE>Airplane</CODE> <I>object</I>.<SCRIPT>create_link(13);</SCRIPT>
</P>
<A NAME="14154"></A>
<P><A NAME="dingp14"></A>
The next thing to do is to write the new <CODE>operator</CODE> <CODE>new</CODE>:<SCRIPT>create_link(14);</SCRIPT>
</P>
<A NAME="14177"></A>
<UL><PRE><A NAME="p42"></A>void * Airplane::operator new(size_t size)
{
  // send requests of the "wrong" size to ::operator new();
  // for details, see <A HREF="./EI8_FR.HTM#120851" TARGET="_top">Item 8</A>
  if (size != sizeof(Airplane))
    return ::operator new(size);
</PRE>
</UL><A NAME="14178"></A>

⌨️ 快捷键说明

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