📄 counting.htm
字号:
<P><A NAME="dingp59"></A><A NAME="AUTO00028"></A>But here is the ambiguity problem. Which <CODE>howMany</CODE> should be made available by <CODE>SpecialWidget</CODE>, the one it inherits from <CODE>Widget</CODE> or the one it inherits from <CODE>Counter<SpecialWidget></CODE>? The one we want, naturally, is the one from <CODE>Counter<SpecialWidget></CODE>, but there's no way to say that without actually writing <CODE>SpecialWidget::howMany</CODE>. Fortunately, it's a simple inline <NOBR>function:<SCRIPT>create_link(59);</SCRIPT>
</NOBR></P>
<A NAME="AUTO00068"></A><UL><PRE>
class SpecialWidget: public Widget,
private Counter<SpecialWidget> {
public:
...
static size_t howMany()
{ return Counter<SpecialWidget>::howMany(); }
...
};
</PRE>
</UL>
<P><A NAME="dingp60"></A>The second observation about our use of inheritance to count objects is that the value returned from <CODE>Widget::howMany</CODE> includes not just the number of <CODE>Widget</CODE> objects, it includes also objects of classes derived from <CODE>Widget</CODE>. If the only class derived from <CODE>Widget</CODE> is <CODE>SpecialWidget</CODE> and there are five stand-alone <CODE>Widget</CODE> objects and three stand-alone <CODE>SpecialWidget</CODE>s, <CODE>Widget::howMany</CODE> will return eight. After all, construction of each <CODE>SpecialWidget</CODE> also entails construction of the base <CODE>Widget</CODE> part. (For a more detailed
examination of this topic, see <SCRIPT>sendmetoo(26,5350,'M');</SCRIPT> onMouseOver = "self.status = 'Item M26'; return true" onMouseOut = "self.status = self.defaultStatus" >Item M26</A>'s treatment of <SCRIPT>sendmetoo(26,'p136','M');</SCRIPT> onMouseOver = "self.status = 'contexts for object construction'; return true" onMouseOut = "self.status = self.defaultStatus">contexts for object construction</A>.)<SCRIPT>create_link(60);</SCRIPT>
</p>
<P><A NAME="dingp61"></A><FONT ID="aititle">Summary</FONT><SCRIPT>create_link(61);</SCRIPT>
</P>
<P><A NAME="dingp62"></A>The following points are really all you need to <NOBR>remember:<SCRIPT>create_link(62);</SCRIPT>
</NOBR></P>
<A NAME="AUTO00029"></A>
<UL>
<A NAME="dingp63"></A><LI>Automating the counting of objects isn't hard, but it's not completely straightforward, either. Use of the "Do It For Me" pattern (Coplien's "curiously recurring template pattern") makes it possible to generate the correct number of counters. The use of private inheritance makes it possible to offer object-counting capabilities without increasing object sizes.<SCRIPT>create_link(63);</SCRIPT>
<A NAME="AUTO00030"></A>
<A NAME="dingp64"></A><LI>When clients have a choice between inheriting from an empty class or containing an object of such a class as a data member, inheritance is preferable, because it allows for more compact objects.<SCRIPT>create_link(64);</SCRIPT>
<A NAME="AUTO00031"></A>
<A NAME="dingp65"></A><LI>Because C++ endeavors to avoid memory leaks when construction fails for heap objects, code that requires access to <CODE>operator</CODE> <CODE>new</CODE> generally requires access to the corresponding <CODE>operator</CODE> <CODE>delete</CODE> too.<SCRIPT>create_link(65);</SCRIPT>
<A NAME="AUTO00032"></A>
<A NAME="dingp66"></A><LI>The <CODE>Counter</CODE> class template doesn't care whether you inherit from it or you contain an object of its type. It looks the same regardless. Hence, clients can freely choose inheritance or containment, even using different strategies in different parts of a single application or library.<SCRIPT>create_link(66);</SCRIPT>
<A NAME="AUTO00033"></A>
</UL>
<A NAME="AUTO00034"></A>
<A NAME="sidebar"></A><A NAME="dingSidebar"></A><BR>
<TABLE WIDTH="95%" ALIGN="center" BORDER="0" CELLSPACING="3" CELLPADDING="3">
<TR><TH BGCOLOR="#000000"><FONT COLOR="#FFFFFF">Sidebar: Placement <code>new</code> and Placement <code>delete</code></FONT></TH></TR>
<TR><TD BGCOLOR="#FFFFFCC">
<p><A NAME="dingp67"></A>The C++ equivalent of <CODE>malloc</CODE> is <CODE>operator</CODE> <CODE>new</CODE>, and the C++ equivalent of <CODE>free</CODE> is <CODE>operator</CODE> <CODE>delete</CODE>. Unlike <CODE>malloc</CODE> and <CODE>free</CODE>, however, <CODE>operator</CODE> <CODE>new</CODE> and <CODE>operator</CODE> <CODE>delete</CODE> are over loadable functions, and as such they may take different numbers and types of parameters. This has always been the case for <CODE>operator</CODE> <CODE>new</CODE>, but until relatively recently, it wasn't valid to overload <CODE>operator</CODE> <CODE>delete</CODE>.<SCRIPT>create_link(67);</SCRIPT>
</p>
<A NAME="AUTO00035"></A>
<p><A NAME="dingp68"></A>The "normal" signature for <CODE>operator</CODE> <CODE>new</CODE> is:<SCRIPT>create_link(68);</SCRIPT>
</p>
<A NAME="AUTO00036"></A>
<A NAME="AUTO00069"></A><PRE>
void * operator new(size_t) throw (std::bad_alloc);
</PRE>
<A NAME="dingp69"></A>(To simplify things from now on, I'll omit exception specifications. They're not germane to the points I want to make here, but you can read about them in <SCRIPT>sendmetoo(15,40989,'M');</SCRIPT> onMouseOver = "self.status = 'Item M15'; return true" onMouseOut = "self.status = self.defaultStatus">Item M15</A></NOBR>.) Overloaded versions of <CODE>operator</CODE> <CODE>new</CODE> are limited to adding additional parameters, so an overloaded version of <CODE>operator</CODE> <CODE>new</CODE> might look like this:<SCRIPT>create_link(69);</SCRIPT>
<A NAME="AUTO00037"></A>
<A NAME="AUTO00070"></A><PRE>
void * operator new(size_t, void *whereToPutObject)
{ return whereToPutObject; }
</PRE>
<A NAME="dingp70"></A>This particular version of <CODE>operator</CODE> <CODE>new</CODE> — the one taking an extra <CODE>void*</CODE> argument specifying what pointer the function should return — is so commonly useful that it's in the Standard C++ library (declared in the header <CODE><new></CODE>) and it has a name, <em>placement <code>new</code></em>. The name indicates its purpose: to allow programmers to specify where in memory an object should be created (i.e., where it should be placed).<SCRIPT>create_link(70);</SCRIPT>
<A NAME="AUTO00038"></A>
<A NAME="dingp71"></A><p>Over time, the term <em>placement <code>new</code></em> has come to be applied to <em>any</em> version of <CODE>operator</CODE> <CODE>new</CODE> taking additional arguments. (This terminology is actually enshrined in the grammar for the <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=cstandard" ONMOUSEOVER = "self.status = 'Standard C++ Library'; return true" ONMOUSEOUT = "self.status = self.defaultStatus" TARGET="_top">International</NOBR> Standard for C++</A>.) Hence, when C++ programmers talk about <I>the</I> placement <CODE>new</CODE> function, they mean the function above, the one taking the extra <CODE>void*</CODE> parameter specifying where an object should be placed. When they talk about <I>a</I> placement <CODE>new</CODE> function, however, they mean <em>any</em> version of operator <CODE>new</CODE> taking more than the mandatory <CODE>size_t</CODE> argument. That includes the function above, but it also includes a plethora of <CODE>operator</CODE> <CODE>new</CODE> functions that take more or different parameter types.<SCRIPT>create_link(71);</SCRIPT>
</p>
<A NAME="AUTO00039"></A>
<A NAME="dingp72"></A><p>In other words, when the topic is memory allocation functions, "placement <CODE>new</CODE>" means "a version of <CODE>operator</CODE> <CODE>new</CODE> taking extra arguments." The term can mean still other things in other contexts, but we don't need to go down that road here, so we won't. For details, consult the <a href="#reading" onMouseOver = "self.status = 'suggested reading'; return true" onMouseOut = "self.status = self.defaultStatus">suggested reading</A></NOBR> at the end of the article.<SCRIPT>create_link(72);</SCRIPT>
</p>
<A NAME="AUTO00040"></A>
<A NAME="dingp73"></A><p>By analogy with placement <CODE>new</CODE>, the term <em>placement <code>delete</code></em> means "a version of <CODE>operator</CODE> <CODE>delete</CODE>
taking extra arguments." The "normal" signature for <CODE>operator</CODE> <CODE>delete</CODE> is<SCRIPT>create_link(73);</SCRIPT>
</p>
<A NAME="AUTO00071"></A><PRE>
void operator delete(void*);
</PRE>
<p><A NAME="dingp74"></A>so any version of <CODE>operator</CODE> <CODE>delete</CODE> taking one or more arguments beyond the mandatory <CODE>void*</CODE> parameter is a placement <CODE>delete</CODE> function.<SCRIPT>create_link(74);</SCRIPT>
</p>
<A NAME="AUTO00041"></A>
<A NAME="dingp75"></A>Let us now revisit an issue discussed in the main article. What happens when an exception is thrown during construction of a heap object? Consider again this simple example:<SCRIPT>create_link(75);</SCRIPT>
<A NAME="AUTO00072"></A><PRE>
class ABCD { ... };
ABCD *p = new ABCD;
</PRE>
<p><A NAME="dingp76"></A>Suppose the attempt to create the <CODE>ABCD</CODE> object yields an exception. The main article pointed out that if that exception came from the <CODE>ABCD</CODE> constructor, <CODE>operator</CODE> <CODE>delete</CODE> would automatically be called to deallocate the memory allocated by <CODE>operator</CODE> <CODE>new</CODE>. But what if <CODE>operator</CODE> <CODE>new</CODE> is overloaded, and what if different versions of <CODE>operator</CODE> <CODE>new</CODE> (quite reasonably) allocate memory in different ways? How can <CODE>operator</CODE> <CODE>delete</CODE> know how to correctly deallocate the memory? Furthermore, what if placement <CODE>new</CODE> was used for the <CODE>ABCD</CODE> object being created, like this?<SCRIPT>create_link(76);</SCRIPT>
</p>
<A NAME="AUTO00073"></A><PRE>
void *objectBuffer = getPointerToStaticBuffer();
ABCD *p = new (objectBuffer) ABCD; // create an ABCD object
// in a static buffer
</PRE>
<p><A NAME="dingp77"></A>(The) placement <CODE>new</CODE> didn't actually allocate any memory. It just returned the pointer to the static buffer that was passed to it in the first place. So there's no need for any deallocation.<SCRIPT>create_link(77);</SCRIPT>
</p>
<A NAME="dingp78"></A><p><A NAME="AUTO00042"></A> Clearly, the actions to be taken in <CODE>operator</CODE> <CODE>delete</CODE> to undo the actions of its corresponding <CODE>operator</CODE> <CODE>new</CODE> depend on the version of <CODE>operator</CODE> <CODE>new</CODE> that was invoked to allocate the memory.<SCRIPT>create_link(78);</SCRIPT>
</p>
<A NAME="dingp79"></A><p><A NAME="AUTO00043"></A>To make it possible for programmers to indicate how the actions of particluar versions of <CODE>operator</CODE> <CODE>new</CODE> can be undone, the C++ Standards committee extended C++ to allow operator delete to be overloaded, too. When an exception is thrown from the constructor for a heap object, then, the game is played in a special way. The version of <CODE>operator</CODE> <CODE>delete</CODE> that's called is the one whose extra parameter types correspond to those of the version of <CODE>operator</CODE> <CODE>new</CODE> that was invoked.<SCRIPT>create_link(79);</SCRIPT>
</p>
<A NAME="AUTO00044"></A><P>
<A NAME="dingp80"></A>If there's no placement <CODE>delete</CODE> whose extra parameters correspond to the extra parameters of the placement <CODE>new</CODE> that was called, no <CODE>operator</CODE> <CODE>delete</CODE> is invoked at all. So the effects of <CODE>operator</CODE> <CODE>new</CODE> are not undone. For functions like (the) placement version of <CODE>operator</CODE> <CODE>new</CODE>, this is fine, because they don't really allocate memory. In general, however, if you create a custom placement version of <CODE>operator</CODE> <CODE>new</CODE>, you should also create the corresponding custom placement version of <CODE>operator</CODE> <CODE>delete</CODE> to go with it.<SCRIPT>create_link(80);</SCRIPT>
</p>
<A NAME="AUTO00045"></A>
<A NAME="dingp81"></A><p>Alas, most compilers don't yet support placement <CODE>delete</CODE>. With code generated from such compilers, you almost always suffer a memory leak if an exception is thrown during construction of a heap object, because no attempt is made to deallocate the memory that was allocated before the constructor was invoked.<SCRIPT>create_link(81);</SCRIPT>
</p>
</TD></TR></TABLE>
<A NAME="AUTO00046"></A>
<P><A NAME="dingp82"></A><FONT ID="aititle">References</FONT><SCRIPT>create_link(82);</SCRIPT>
</P>
<OL>
<a name="ref1">
<A NAME="dingp83"></A><LI><NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=jcoplien" onMouseOver = "self.status = 'Jim Coplien Personal Site'; return true" onMouseOut = "self.status = self.defaultStatus" target="_top">James</NOBR> O. Coplien</A></NOBR>, "The Column Without a Name: A Curiously Recurring Template Pattern," <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=cppreport" onMouseOver = "self.status = 'C++ Report Home Page'; return true" onMouseOut = "self.status = self.defaultStatus" target="_top"><I>C++</NOBR> Report</I></A></NOBR>, February 1995.<SCRIPT>create_link(83);</SCRIPT>
</A></NOBR>
<A NAME="AUTO00047"></A>
<a name="ref2">
<A NAME="dingp84"></A><LI><NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=nmyers" onMouseOver = "self.status = 'Nathan Myers Personal Site'; return true" onMouseOut = "self.status = self.defaultStatus" target="_top">Nathan</NOBR> Myers</A></NOBR>, "<NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=emptyopt" onMouseOver = "self.status = 'The Empty Member C++ Optimization'; return true" onMouseOut = "self.status = self.defaultStatus" target="_top">The</NOBR> Empty Member C++ Optimization</A></NOBR>," <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=ddj" onMouseOver = "self.status = 'Dr. Dobbs Journal Home Page'; return true" onMouseOut = "self.status = self.defaultStatus" target="_top"><I>Dr. Dobbs Journal</I></A></NOBR>, August 1997.<SCRIPT>create_link(84);</SCRIPT>
</A></NOBR>
</OL>
<P><A NAME="dingp85"></A><a name="reading"><FONT ID="aititle">Suggested Reading</FONT></A><SCRIPT>create_link(85);</SCRIPT>
</P>
<P><A NAME="dingp86"></A>To learn more about the details of <CODE>new</CODE> and <CODE>delete</CODE>, read the columns by Dan Saks</A> on the topic (<NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=cuj" onMouseOver = "self.status = 'C/C++ Users Journal Home Page'; return true" onMouseOut = "self.status = self.defaultStatus" target="_top"><I>CUJ</I></A></NOBR> January - July 1997) or turn to <SCRIPT>sendmetoo(8,33985,'M');</SCRIPT> onMouseOver = "self.status = 'Item M8'; return true" onMouseOut = "self.status = self.defaultStatus">Item M8</A></NOBR>. For a broader examination of the object-counting problem, including how to limit the number of instantiations of a class, consult <SCRIPT>sendmetoo(26,5350,'M');</SCRIPT> onMouseOver = "self.status = 'Item M26'; return true" onMouseOut = "self.status = self.defaultStatus">Item M26</A></NOBR>.<SCRIPT>create_link(86);</SCRIPT>
</P>
<P><A NAME="dingp87"></A><FONT ID="aititle">Acknowledgments</FONT><SCRIPT>create_link(87);</SCRIPT>
</P>
<P><A NAME="dingp88"></A>Mark Rodgers, Damien Watkins, Marco Dalla Gasperina, and Bobby Schmidt provided comments on drafts of this article. Their insights and suggestions improved it in several <NOBR>ways.<SCRIPT>create_link(88);</SCRIPT>
</NOBR></P>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -