📄 chap03.htm
字号:
<font color=#009900>// Comment out the following to send all the</font>
<font color=#009900>// information to the trace file:</font>
#define memtrace stdout
<font color=#0000ff>const</font> <font color=#0000ff>unsigned</font> <font color=#0000ff>long</font> _pool_sz = 50000L;
<font color=#0000ff>static</font> <font color=#0000ff>unsigned</font> <font color=#0000ff>char</font> _memory_pool[_pool_sz];
<font color=#0000ff>static</font> <font color=#0000ff>unsigned</font> <font color=#0000ff>char</font>* _pool_ptr = _memory_pool;
<font color=#0000ff>void</font>* getmem(size_t sz) {
<font color=#0000ff>if</font>(_memory_pool + _pool_sz - _pool_ptr < sz) {
fprintf(stderr,
<font color=#004488>"Out of memory. Use bigger model\n"</font>);
exit(1);
}
<font color=#0000ff>void</font>* p = _pool_ptr;
_pool_ptr += sz;
<font color=#0000ff>return</font> p;
}
<font color=#009900>// Holds information about allocated pointers:</font>
<font color=#0000ff>class</font> MemBag {
<font color=#0000ff>public</font>:
<font color=#0000ff>enum</font> type { Malloc, New };
<font color=#0000ff>private</font>:
<font color=#0000ff>char</font>* typestr(type t) {
<font color=#0000ff>switch</font>(t) {
<font color=#0000ff>case</font> Malloc: <font color=#0000ff>return</font> <font color=#004488>"malloc"</font>;
<font color=#0000ff>case</font> New: <font color=#0000ff>return</font> <font color=#004488>"new"</font>;
<font color=#0000ff>default</font>: <font color=#0000ff>return</font> <font color=#004488>"?unknown?"</font>;
}
}
<font color=#0000ff>struct</font> M {
<font color=#0000ff>void</font>* mp; <font color=#009900>// Memory pointer</font>
type t; <font color=#009900>// Allocation type</font>
<font color=#0000ff>char</font>* file; <font color=#009900>// File name where allocated</font>
<font color=#0000ff>int</font> line; <font color=#009900>// Line number where allocated</font>
M(<font color=#0000ff>void</font>* v, type tt, <font color=#0000ff>char</font>* f, <font color=#0000ff>int</font> l)
: mp(v), t(tt), file(f), line(l) {}
}* v;
<font color=#0000ff>int</font> sz, next;
<font color=#0000ff>enum</font> { increment = 50 };
<font color=#0000ff>public</font>:
MemBag() : v(0), sz(0), next(0) {}
<font color=#0000ff>void</font>* add(<font color=#0000ff>void</font>* p, type tt = Malloc,
<font color=#0000ff>char</font>* s = <font color=#004488>"library"</font>, <font color=#0000ff>int</font> l = 0) {
<font color=#0000ff>if</font>(next >= sz) {
sz += increment;
<font color=#009900>// This memory is never freed, so it</font>
<font color=#009900>// doesn't "get involved" in the test:</font>
<font color=#0000ff>const</font> <font color=#0000ff>int</font> memsize = sz * <font color=#0000ff>sizeof</font>(M);
<font color=#009900>// Equivalent of realloc, no registration:</font>
<font color=#0000ff>void</font>* p = getmem(memsize);
<font color=#0000ff>if</font>(v) memmove(p, v, memsize);
v = (M*)p;
memset(&v[next], 0,
increment * <font color=#0000ff>sizeof</font>(M));
}
v[next++] = M(p, tt, s, l);
<font color=#0000ff>return</font> p;
}
<font color=#009900>// Print information about allocation:</font>
<font color=#0000ff>void</font> allocation(<font color=#0000ff>int</font> i) {
fprintf(memtrace, <font color=#004488>"pointer %p"</font>
<font color=#004488>" allocated with %s"</font>,
v[i].mp, typestr(v[i].t));
<font color=#0000ff>if</font>(v[i].t == New)
fprintf(memtrace, <font color=#004488>" at %s: %d"</font>,
v[i].file, v[i].line);
fprintf(memtrace, <font color=#004488>"\n"</font>);
}
<font color=#0000ff>void</font> validate(<font color=#0000ff>void</font>* p, type T = Malloc) {
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < next; i++)
<font color=#0000ff>if</font>(v[i].mp == p) {
<font color=#0000ff>if</font>(v[i].t != T) {
allocation(i);
fprintf(memtrace,
<font color=#004488>"\t was released as if it were "</font>
<font color=#004488>"allocated with %s \n"</font>, typestr(T));
}
v[i].mp = 0; <font color=#009900>// Erase it</font>
<font color=#0000ff>return</font>;
}
fprintf(memtrace,
<font color=#004488>"pointer not in memory list: %p\n"</font>, p);
}
~MemBag() {
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < next; i++)
<font color=#0000ff>if</font>(v[i].mp != 0) {
fprintf(memtrace,
<font color=#004488>"pointer not released: "</font>);
allocation(i);
}
}
};
<font color=#0000ff>extern</font> MemBag MEMBAG_;
<font color=#0000ff>void</font>* malloc(size_t sz) {
<font color=#0000ff>void</font>* p = getmem(sz);
<font color=#0000ff>return</font> MEMBAG_.add(p, MemBag::Malloc);
}
<font color=#0000ff>void</font>* calloc(size_t num_elems, size_t elem_sz) {
<font color=#0000ff>void</font>* p = getmem(num_elems * elem_sz);
memset(p, 0, num_elems * elem_sz);
<font color=#0000ff>return</font> MEMBAG_.add(p, MemBag::Malloc);
}
<font color=#0000ff>void</font>* realloc(<font color=#0000ff>void</font>* block, size_t sz) {
<font color=#0000ff>void</font>* p = getmem(sz);
<font color=#0000ff>if</font>(block) memmove(p, block, sz);
<font color=#0000ff>return</font> MEMBAG_.add(p, MemBag::Malloc);
}
<font color=#0000ff>void</font> free(<font color=#0000ff>void</font>* v) {
MEMBAG_.validate(v, MemBag::Malloc);
}
<font color=#0000ff>void</font>* <font color=#0000ff>operator</font> <font color=#0000ff>new</font>(size_t sz) {
<font color=#0000ff>void</font>* p = getmem(sz);
<font color=#0000ff>return</font> MEMBAG_.add(p, MemBag::New);
}
<font color=#0000ff>void</font>*
<font color=#0000ff>operator</font> <font color=#0000ff>new</font>(size_t sz, <font color=#0000ff>char</font>* file, <font color=#0000ff>int</font> line) {
<font color=#0000ff>void</font>* p = getmem(sz);
<font color=#0000ff>return</font> MEMBAG_.add(p, MemBag::New, file, line);
}
<font color=#0000ff>void</font> <font color=#0000ff>operator</font> <font color=#0000ff>delete</font>(<font color=#0000ff>void</font>* v) {
MEMBAG_.validate(v, MemBag::New);
}
MemBag MEMBAG_;
<font color=#009900>// Placed here so the constructor is called</font>
<font color=#009900>// AFTER that of MEMBAG_ :</font>
#ifdef memtrace
#undef memtrace
#endif
OFile memtrace(<font color=#004488>"memtrace.out"</font>);
<font color=#009900>// Causes 1 "pointer not in memory list" message</font>
<font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>OFile</B> is a simple wrapper around a
<B>FILE*</B>; the constructor opens the file and the destructor closes it. The
<B>operator FILE*( )</B> allows you to simply use the <B>OFile</B> object
anyplace you would ordinarily use a <B>FILE*</B> (in the <B>fprintf( )</B>
statements in this example). The <B>#define</B> that follows simply sends
everything to standard output, but if you need to put it in a trace file you
simply comment out that line.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Memory is allocated from an array called
<B>_memory_pool</B>. The <B>_pool_ptr</B> is moved forward every time storage is
allocated. For simplicity, the storage is never reclaimed, and
<B>realloc( )</B> doesn’t try to resize the storage in the same
place.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">All the storage allocation functions call
<B>getmem( )</B> which ensures there is enough space left and moves the
<B>_pool_ptr</B> to allocate your storage. Then they store the pointer in a
special container of class <B>MemBag</B> called <B>MEMBAG_</B>, along with
pertinent information (notice the two versions of <B>operator new</B>; one which
just stores the pointer and the other which stores the file and line number).
The <B>MemBag</B> class is the heart of the system.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You will see many similarities to
<B>xbag</B> in <B>MemBag</B>. A distinct difference is <B>realloc( )</B> is
replaced by a call to <B>getmem( )</B> and <B>memmove( )</B>, so that
storage allocated for the <B>MemBag</B> is not registered. In addition, the
<B>type</B> <B>enum</B> allows you to store the way the memory was allocated;
the <B>typestr( )</B> function takes a type and produces a string for use
with printing.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The nested <B>struct M</B> holds the
pointer, the type, a pointer to the file name (which is assumed to be statically
allocated) and the line where the allocation occurred. <B>v</B> is a pointer to
an array of <B>M</B> objects – this is the array which is dynamically
sized.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>allocation( )</B> function
prints out a different message depending on whether the storage was allocated
with <B>new</B> (where it has line and file information) or
<B>malloc( )</B> (where it doesn’t). This function is used inside
<B>validate( )</B>, which is called by <B>free( )</B> and
<B>delete( )</B> to ensure everything is OK, and in the destructor, to
ensure the pointer was cleaned up (note that in <B>validate( )</B> the
pointer value <B>v[i].mp</B> is set to zero, to indicate it has been cleaned
up).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The following is a simple test using the
memcheck facility. The <B>MemCheck.obj</B> file must be linked in for it to
work:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C03:MemTest.cpp</font>
<font color=#009900>//{L} MemCheck</font>
<font color=#009900>//{-msc}</font>
<font color=#009900>// Test of MemCheck system</font>
#include <font color=#004488>"MemCheck.h"</font>
<font color=#0000ff>int</font> main() {
<font color=#0000ff>void</font>* v = std::malloc(100);
<font color=#0000ff>delete</font> v;
<font color=#0000ff>int</font>* x = <font color=#0000ff>new</font> <font color=#0000ff>int</font>;
std::free(x);
<font color=#0000ff>new</font> <font color=#0000ff>double</font>;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The trace file created in
<B>MemCheck.cpp</B> causes the generation of one "pointer not in memory list"
message, apparently from the creation of the file pointer on the heap. [[ This
may not still be true – test it
]]</FONT><A NAME="_Toc519041919"></A><BR></P></DIV>
<A NAME="Heading78"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
The canonical object & singly-rooted
hierarchies<A NAME="_Toc519041920"></A></H2></FONT>
<A NAME="Heading79"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
An extended canonical form</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Including a set of methods (such as
trace/print/dump) in your library’s base class to enable easy
debugging.</FONT><A NAME="_Toc519041921"></A><BR></P></DIV>
<A NAME="Heading80"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Exercises</H2></FONT>
<OL>
<LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">Create a heap compactor
for all dynamic memory in a particular program. This will require that you
control how objects are dynamically created and used (do you overload
<B>operator new</B> or does that approach work?). The typical heap-compaction
scheme requires that all pointers are doubly-indirected (that is, pointers to
pointers) so the “middle tier” pointer can be manipulated during
compaction. Consider overloading <B>operator-></B> to accomplish this, since
that operator has special behavior which will probably benefit your
heap-compaction scheme. Write a program to test your heap-compaction
scheme.</FONT></OL>
<DIV ALIGN="CENTER">
<FONT FACE="Verdana, Tahoma, Arial, Helvetica, Sans" size = "-1">
[ <a href="Chap02.htm">Previous Chapter</a> ]
[ <a href="SimpCont.htm">Short TOC</a> ]
[ <a href="Contents.htm">Table of Contents</a> ]
[ <a href="DocIdx.htm">Index</a> ]
[ <a href="Part2.htm">Next Chapter</a> ]
</FONT>
<BR>
Last Update:09/26/2001</P></DIV>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -