📄 chapter16.html
字号:
inlined:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C16:TStack.h</font>
<font color=#009900>// The Stack as a template</font>
#ifndef TSTACK_H
#define TSTACK_H
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T>
<font color=#0000ff>class</font> Stack {
<font color=#0000ff>struct</font> Link {
T* data;
Link* next;
Link(T* dat, Link* nxt):
data(dat), next(nxt) {}
}* head;
<font color=#0000ff>public</font>:
Stack() : head(0) {}
~Stack(){
<font color=#0000ff>while</font>(head)
<font color=#0000ff>delete</font> pop();
}
<font color=#0000ff>void</font> push(T* dat) {
head = <font color=#0000ff>new</font> Link(dat, head);
}
T* peek() <font color=#0000ff>const</font> {
<font color=#0000ff>return</font> head ? head->data : 0;
}
T* pop(){
<font color=#0000ff>if</font>(head == 0) <font color=#0000ff>return</font> 0;
T* result = head->data;
Link* oldHead = head;
head = head->next;
<font color=#0000ff>delete</font> oldHead;
<font color=#0000ff>return</font> result;
}
};
#endif <font color=#009900>// TSTACK_H ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you compare this to the
<B>OStack.h</B> example at the end of Chapter 15, you will see that <B>Stack</B>
is virtually identical, except that <B>Object</B> has been replaced with
<B>T</B>. The test program is also nearly identical, except that the necessity
for multiply-inheriting from <B>string</B> and <B>Object</B> (and even the need
for <B>Object </B>itself) has been eliminated. Now there is no <B>MyString</B>
class to announce its destruction, so a small new class is added to show a
<B>Stack </B>container cleaning up its objects:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C16:TStackTest.cpp</font>
<font color=#009900>//{T} TStackTest.cpp</font>
#include <font color=#004488>"TStack.h"</font>
#include <font color=#004488>"../require.h"</font>
#include <fstream>
#include <iostream>
#include <string>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> X {
<font color=#0000ff>public</font>:
<font color=#0000ff>virtual</font> ~X() { cout << <font color=#004488>"~X "</font> << endl; }
};
<font color=#0000ff>int</font> main(<font color=#0000ff>int</font> argc, <font color=#0000ff>char</font>* argv[]) {
requireArgs(argc, 1); <font color=#009900>// File name is argument</font>
ifstream in(argv[1]);
assure(in, argv[1]);
Stack<string> textlines;
string line;
<font color=#009900>// Read file and store lines in the Stack:</font>
<font color=#0000ff>while</font>(getline(in, line))
textlines.push(<font color=#0000ff>new</font> string(line));
<font color=#009900>// Pop some lines from the stack:</font>
string* s;
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < 10; i++) {
<font color=#0000ff>if</font>((s = (string*)textlines.pop())==0) <font color=#0000ff>break</font>;
cout << *s << endl;
<font color=#0000ff>delete</font> s;
} <font color=#009900>// The destructor deletes the other strings.</font>
<font color=#009900>// Show that correct destruction happens:</font>
Stack<X> xx;
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 0; j < 10; j++)
xx.push(<font color=#0000ff>new</font> X);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The
<A NAME="Index2655"></A><A NAME="Index2656"></A>destructor for <B>X</B> is
virtual, not because it’s necessary here, but because <B>xx</B> could
later be used to hold objects derived from <B>X</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice how easy it is to create different
kinds of <B>Stack</B>s for <B>string</B> and for <B>X</B>.<B> </B>Because of the
template, you get the best of both worlds: the ease of use of the <B>Stack</B>
class along with proper cleanup.</FONT><A NAME="_Toc472655056"></A><BR></P></DIV>
<A NAME="Heading475"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Templatized pointer Stash<BR><A NAME="Index2657"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Reorganizing the <B>PStash</B> code into
a template isn’t quite so simple because there are a number of member
functions that should not be
<A NAME="Index2658"></A><A NAME="Index2659"></A>inlined. However, as a template
those function definitions still belong in the
<A NAME="Index2660"></A><A NAME="Index2661"></A>header file (the compiler and
linker take care of any multiple definition problems). The code looks quite
similar to the ordinary <B>PStash</B> except that you’ll notice the size
of the increment (used by <B>inflate( )</B>) has been templatized as a
non-class parameter with a default value, so that the increment size can be
modified at the point of instantiation (notice that this means that the
increment size is fixed; you may also argue that the increment size should be
changeable throughout the lifetime of the object):</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C16:TPStash.h</font>
#ifndef TPSTASH_H
#define TPSTASH_H
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr = 10>
<font color=#0000ff>class</font> PStash {
<font color=#0000ff>int</font> quantity; <font color=#009900>// Number of storage spaces</font>
<font color=#0000ff>int</font> next; <font color=#009900>// Next empty space</font>
T** storage;
<font color=#0000ff>void</font> inflate(<font color=#0000ff>int</font> increase = incr);
<font color=#0000ff>public</font>:
PStash() : quantity(0), next(0), storage(0) {}
~PStash();
<font color=#0000ff>int</font> add(T* element);
T* <font color=#0000ff>operator</font>[](<font color=#0000ff>int</font> index) <font color=#0000ff>const</font>; <font color=#009900>// Fetch</font>
<font color=#009900>// Remove the reference from this PStash:</font>
T* remove(<font color=#0000ff>int</font> index);
<font color=#009900>// Number of elements in Stash:</font>
<font color=#0000ff>int</font> count() <font color=#0000ff>const</font> { <font color=#0000ff>return</font> next; }
};
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr>
<font color=#0000ff>int</font> PStash<T, incr>::add(T* element) {
<font color=#0000ff>if</font>(next >= quantity)
inflate(incr);
storage[next++] = element;
<font color=#0000ff>return</font>(next - 1); <font color=#009900>// Index number</font>
}
<font color=#009900>// Ownership of remaining pointers:</font>
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr>
PStash<T, incr>::~PStash() {
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < next; i++) {
<font color=#0000ff>delete</font> storage[i]; <font color=#009900>// Null pointers OK</font>
storage[i] = 0; <font color=#009900>// Just to be safe</font>
}
<font color=#0000ff>delete</font> []storage;
}
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr>
T* PStash<T, incr>::<font color=#0000ff>operator</font>[](<font color=#0000ff>int</font> index) <font color=#0000ff>const</font> {
require(index >= 0,
<font color=#004488>"PStash::operator[] index negative"</font>);
<font color=#0000ff>if</font>(index >= next)
<font color=#0000ff>return</font> 0; <font color=#009900>// To indicate the end</font>
require(storage[index] != 0,
<font color=#004488>"PStash::operator[] returned null pointer"</font>);
<font color=#009900>// Produce pointer to desired element:</font>
<font color=#0000ff>return</font> storage[index];
}
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr>
T* PStash<T, incr>::remove(<font color=#0000ff>int</font> index) {
<font color=#009900>// operator[] performs validity checks:</font>
T* v = <font color=#0000ff>operator</font>[](index);
<font color=#009900>// "Remove" the pointer:</font>
<font color=#0000ff>if</font>(v != 0) storage[index] = 0;
<font color=#0000ff>return</font> v;
}
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> incr>
<font color=#0000ff>void</font> PStash<T, incr>::inflate(<font color=#0000ff>int</font> increase) {
<font color=#0000ff>const</font> <font color=#0000ff>int</font> psz = <font color=#0000ff>sizeof</font>(T*);
T** st = <font color=#0000ff>new</font> T*[quantity + increase];
memset(st, 0, (quantity + increase) * psz);
memcpy(st, storage, quantity * psz);
quantity += increase;
<font color=#0000ff>delete</font> []storage; <font color=#009900>// Old storage</font>
storage = st; <font color=#009900>// Point to new memory</font>
}
#endif <font color=#009900>// TPSTASH_H ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The default increment size used here is
small to guarantee that calls to <B>inflate( ) </B>occur. This way we can
make sure it works correctly.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To test the
<A NAME="Index2662"></A>ownership control of the templatized <B>PStash</B>, the
following class will report
<A NAME="Index2663"></A><A NAME="Index2664"></A>creations and destructions of
itself, and also guarantee that all objects that have been created were also
destroyed. <B>AutoCounter</B> will allow only objects of its type to be created
on the
stack<A NAME="Index2665"></A><A NAME="Index2666"></A><A NAME="Index2667"></A><A NAME="Index2668"></A>:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C16:AutoCounter.h</font>
#ifndef AUTOCOUNTER_H
#define AUTOCOUNTER_H
#include <font color=#004488>"../require.h"</font>
#include <iostream>
#include <set> <font color=#009900>// Standard C++ Library container</font>
#include <string>
<font color=#0000ff>class</font> AutoCounter {
<font color=#0000ff>static</font> <font color=#0000ff>int</font> count;
<font color=#0000ff>int</font> id;
<font color=#0000ff>class</font> CleanupCheck {
std::set<AutoCounter*> trace;
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font> add(AutoCounter* ap) {
trace.insert(ap);
}
<font color=#0000ff>void</font> remove(AutoCounter* ap) {
require(trace.erase(ap) == 1,
<font color=#004488>"Attempt to delete AutoCounter twice"</font>);
}
~CleanupCheck() {
std::cout << <font color=#004488>"~CleanupCheck()"</font><< std::endl;
require(trace.size() == 0,
<font color=#004488>"All AutoCounter objects not cleaned up"</font>);
}
};
<font color=#0000ff>static</font> CleanupCheck verifier;
AutoCounter() : id(count++) {
verifier.add(<font color=#0000ff>this</font>); <font color=#009900>// Register itself</font>
std::cout << <font color=#004488>"created["</font> << id << <font color=#004488>"]"</font>
<< std::endl;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -