📄 counting.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML>
<HEAD>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>
<TITLE>Counting Objects in C++</TITLE>
<SCRIPT LANGUAGE="JavaScript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript">var imagemax = 0; setCurrentMax(0);</SCRIPT>
<SCRIPT LANGUAGE="JavaScript" SRC="../JAVA/SENDMETO.JS"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT>
var dingbase = "CO_DIR.HTM";
var dingtext = "Meyers, P";
if (self == top) {
top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>
</HEAD>
<BODY bgcolor="#ffffff" OnLoad="setResize()">
<!-- SectionName="Meyers' Counting Objects in C++" -->
<HR SIZE="1" NOSHADE>
<FONT COLOR="#663300" FACE="Helvetica" SIZE=-1>
<B>This is a slightly-modified version of an article that appeared in the April 1998 issue of the <NOBR><FONT COLOR="#FF0000" SIZE="-2">°</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>C/C++</NOBR> Users Journal</I></A>.</B>
</FONT>
<HR SIZE="1" NOSHADE>
<P><A NAME="dingp1"></A><FONT ID="agtitle">Counting Objects in C++</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>
<P><A NAME="dingp2"></A><A NAME="AUTO00001"></A><FONT FACE="Arial" SIZE="+1">by <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=smeyers" onMouseOver = "self.status = 'Scott Meyers Home Page'; return true" onMouseOut = "self.status = self.defaultStatus" target="_top">Scott</NOBR> Meyers</A></FONT><SCRIPT>create_link(2);</SCRIPT>
</P>
<P><A NAME="dingp3"></A><A NAME="AUTO00002"></A>Sometimes easy things are easy, but they're still subtle. For example, suppose you have a class <CODE>Widget</CODE>, and you'd like to have a way to find out at run time how many <CODE>Widget</CODE> objects exist. An approach that's both easy to implement and that gives the right answer is to create a static counter in <CODE>Widget</CODE>, increment the counter each time a <CODE>Widget</CODE> constructor is called, and decrement it whenever the <CODE>Widget</CODE> destructor is called. You also need a static member function <CODE>howMany</CODE> to report how many <CODE>Widgets</CODE> currently exist. If <CODE>Widget</CODE> did nothing but track how many of its type exist, it would look more or less like <NOBR>this:<SCRIPT>create_link(3);</SCRIPT>
</NOBR></p>
<A NAME="AUTO00048"></A><UL><PRE>
class Widget {
public:
Widget() { ++count; }
Widget(const Widget&) { ++count; }
~Widget() { --count; }
static size_t howMany()
{ return count; }
private:
static size_t count;
};
// obligatory definition of count. This
// goes in an implementation file
size_t Widget::count = 0;</PRE>
</UL>
<P><A NAME="dingp4"></A>This works fine. The only mildly tricky thing is to remember to implement the copy constructor, because a compiler-generated copy constructor for <CODE>Widget</CODE> wouldn't know to increment <CODE>count</CODE>.<SCRIPT>create_link(4);</SCRIPT>
</P>
<P><A NAME="dingp5"></A><A NAME="AUTO00003"></A>If you had to do this only for <CODE>Widget</CODE>, you'd be done, but counting objects is something you might want to implement for several classes. Doing the same thing over and over gets tedious, and tedium leads to errors. To forestall such tedium, it would be best to somehow package the above object-counting code so it could be reused in any class that wanted it. The ideal package <NOBR>would:<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<UL>
<A NAME="dingp6"></A><LI>Be easy to use — require minimal work on the part of class authors who want to use it. Ideally, they shouldn't have to do more than one thing, that is, more than basically say "I want to count the objects of this type."<SCRIPT>create_link(6);</SCRIPT>
<A NAME="AUTO00004"></A>
<A NAME="dingp7"></A><LI>Be efficient — impose no unnecessary space or time penalties on client classes employing the package.<SCRIPT>create_link(7);</SCRIPT>
<A NAME="AUTO00005"></A>
<A NAME="dingp8"></A><LI>Be foolproof — be next to impossible to accidentally yield a count that is incorrect. (We're not going to worry about malicious clients, ones who deliberately try to mess up the count. In C++, such clients can always find a way to do their dirty deeds.)<SCRIPT>create_link(8);</SCRIPT>
</UL>
<P><A NAME="dingp9"></A>Stop for a moment and think about how you'd implement a reusable object-counting package that satisfies the goals above. It's probably harder than you expect. If it were as easy as it seems like it should be, you wouldn't be reading an article about it in this <NOBR>magazine.<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp10"></A><FONT ID="aititle"><CODE>new</CODE>, <CODE>delete</CODE>, and Exceptions</FONT><SCRIPT>create_link(10);</SCRIPT>
</P>
<P><A NAME="dingp11"></A>While you're mulling over your solution to the object-counting problem, allow me to switch to what seems like an unrelated topic. That topic is the relationship between <CODE>new</CODE> and <CODE>delete</CODE> when constructors throw exceptions. When you ask C++ to dynamically allocate an object, you use a <em><code>new</code> expression</em>, as <NOBR>in:<SCRIPT>create_link(11);</SCRIPT>
</NOBR></P>
<A NAME="AUTO00049"></A>
<UL><PRE>class ABCD { ... }; // ABCD = "A Big Complex Datatype"
ABCD *p = new ABCD; // "new ABCD" is a new expression</PRE>
</UL>
<P><A NAME="dingp12"></A>The <CODE>new</CODE> expression — whose meaning is built into the language and whose behavior you cannot change — does two things. First, it calls a memory allocation function called <CODE>operator</CODE> <CODE>new</CODE>. That function is responsible for finding enough memory to hold an <CODE>ABCD</CODE> object. If the call to <CODE>operator</CODE> <CODE>new</CODE> succeeds, the <CODE>new</CODE> expression then invokes an <CODE>ABCD</CODE> constructor on the memory that <CODE>operator</CODE> <CODE>new</CODE> <NOBR>found.<SCRIPT>create_link(12);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp13"></A><A NAME="AUTO00006"></A>But suppose <CODE>operator</CODE> <CODE>new</CODE> throws a <CODE>std::bad_alloc</CODE> <NOBR>exception:<SCRIPT>create_link(13);</SCRIPT>
</NOBR></P>
<A NAME="AUTO00050"></A><UL><PRE>
ABCD *p = new ABCD; // suppose a std::bad_alloc is thrown here
</PRE>
</UL>
<P><A NAME="dingp14"></A>Exceptions of this type indicate that an attempt to dynamically allocate memory has failed. In the <CODE>new</CODE> expression above, there are two functions that might give rise to that exception. The first is the invocation of <CODE>operator</CODE> <CODE>new</CODE> that is supposed to find enough memory to hold an <CODE>ABCD</CODE> object. The second is the subsequent invocation of the <CODE>ABCD</CODE> constructor that is supposed to turn the raw memory into a valid <CODE>ABCD</CODE> <NOBR>object.<SCRIPT>create_link(14);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp15"></A><A NAME="AUTO00007"></A>If the exception came from the call to <CODE>operator</CODE> <CODE>new</CODE>, no memory was allocated. However, if the call to <CODE>operator</CODE> <CODE>new</CODE> succeeded and the invocation of the <CODE>ABCD</CODE> constructor led to the exception, it is important that the memory allocated by <CODE>operator</CODE> <CODE>new</CODE> be deallocated. If it's not, the program has a memory leak, because it's not possible for the client — the code requesting creation of the <CODE>ABCD</CODE> object — to determine which function gave rise to the <NOBR>exception.<SCRIPT>create_link(15);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp16"></A><A NAME="AUTO00008"></A>For many years this was a hole in the draft C++ language specification, but in March 1995 the C++ Standards committee adopted the rule that if, during a <CODE>new</CODE> expression, the invocation of <CODE>operator</CODE> <CODE>new</CODE> succeeds and the subsequent constructor call throws an exception, the runtime system must automatically deallocate the memory that <CODE>operator</CODE> <CODE>new</CODE> allocated. This de-allocation is performed by <CODE>operator</CODE> <CODE>delete</CODE>, the de-allocation analogue of <CODE>operator</CODE> <CODE>new</CODE>. (For details, see <a href="counting.htm#sidebar" onMouseOver = "self.status = 'the sidebar on placement new and placement delete'; return true" onMouseOut = "self.status = self.defaultStatus">the sidebar on placement <CODE>new</CODE> and placement <CODE>delete</CODE></A></NOBR>.)<SCRIPT>create_link(16);</SCRIPT>
</P>
<P><A NAME="dingp17"></A><A NAME="AUTO00009"></A>It is this relationship between <CODE>new</CODE> expressions and <CODE>operator</CODE> <CODE>delete</CODE> that affects us in our attempt to automate the counting of object <NOBR>instantiations.<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp18"></A><FONT ID="aititle">Counting Objects</FONT><SCRIPT>create_link(18);</SCRIPT>
</P>
<P><A NAME="dingp19"></A>In all likelihood, your solution to the object-counting problem involved the development of an object-counting class. Your class probably looks remarkably like — perhaps even exactly like — the <CODE>Widget</CODE> class I showed <NOBR>earlier:<SCRIPT>create_link(19);</SCRIPT>
</NOBR></P>
<A NAME="AUTO00051"></A>
<UL><PRE>class Counter { // see below for a discussion of
public: // why this isn't quite right
Counter() { ++count; }
Counter(const Counter&) { ++count; }
~Counter() { --count; }
static size_t howMany()
{ return count; }
private:
static size_t count;
};
// This still goes in an
// implementation file
size_t Counter::count = 0;</PRE>
</UL>
<P><A NAME="dingp20"></A>The idea here is that authors of classes that need to count the number of objects in existence simply use <CODE>Counter</CODE> to take care of the bookkeeping. There are two obvious ways to do this. One way is to define a <CODE>Counter</CODE> object as a class data member, like <NOBR>this:<SCRIPT>create_link(20);</SCRIPT>
</NOBR></P>
<A NAME="AUTO00052"></A>
<UL><PRE>// embed a Counter to count objects
class Widget {
public:
... // all the usual public Widget stuff
static size_t howMany()
{ return Counter::howMany(); }
private:
... // all the usual private Widget stuff
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -