对于大多数容器类,有迭代器是有意义的
//: C16:TPStash2.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
// Templatized PStash with nested iterator
#ifndef TPSTASH2_H
#define TPSTASH2_H
#include "../require.h"
#include <cstdlib>
template<class T, int incr = 20>
class PStash {
int quantity;
int next;
T** storage;
void inflate(int increase = incr);
public:
PStash() : quantity(0), storage(0), next(0) {}
~PStash();
int add(T* element);
T* operator[](int index) const;
T* remove(int index);
int count() const { return next; }
// Nested iterator class:
class iterator; // Declaration required
friend class iterator; // Make it a friend
class iterator { // Now define it
PStash& ps;
int index;
public:
iterator(PStash& pStash)
: ps(pStash), index(0) {}
// To create the end sentinel:
iterator(PStash& pStash, bool)
: ps(pStash), index(ps.next) {}
// Copy-constructor:
iterator(const iterator& rv)
: ps(rv.ps), index(rv.index) {}
iterator& operator=(const iterator& rv) {
ps = rv.ps;
index = rv.index;
return *this;
}
iterator& operator++() {
require(++index <= ps.next,
"PStash::iterator::operator++ "
"moves index out of bounds");
return *this;
}
iterator& operator++(int) {
return operator++();
}
iterator& operator--() {
require(--index >= 0,
"PStash::iterator::operator-- "
"moves index out of bounds");
return *this;
}
iterator& operator--(int) {
return operator--();
}
// Jump interator forward or backward:
iterator& operator+=(int amount) {
require(index + amount < ps.next &&
index + amount >= 0,
"PStash::iterator::operator+= "
"attempt to index out of bounds");
index += amount;
return *this;
}
iterator& operator-=(int amount) {
require(index - amount < ps.next &&
index - amount >= 0,
"PStash::iterator::operator-= "
"attempt to index out of bounds");
index -= amount;
return *this;
}
// Create a new iterator that's moved forward
iterator operator+(int amount) const {
iterator ret(*this);
ret += amount; // op+= does bounds check
return ret;
}
T* current() const {
return ps.storage[index];
}
T* operator*() const { return current(); }
T* operator->() const {
require(ps.storage[index] != 0,
"PStash::iterator::operator->returns 0");
return current();
}
// Remove the current element:
T* remove(){
return ps.remove(index);
}
// Comparison tests for end:
bool operator==(const iterator& rv) const {
return index == rv.index;
}
bool operator!=(const iterator& rv) const {
return index != rv.index;
}
};
iterator begin() { return iterator(*this); }
iterator end() { return iterator(*this, true);}
};
// Destruction of contained objects:
template<class T, int incr>
PStash<T, incr>::~PStash() {
for(int i = 0; i < next; i++) {
delete storage[i]; // Null pointers OK
storage[i] = 0; // Just to be safe
}
delete []storage;
}
template<class T, int incr>
int PStash<T, incr>::add(T* element) {
if(next >= quantity)
inflate();
storage[next++] = element;
return(next - 1); // Index number
}
template<class T, int incr> inline
T* PStash<T, incr>::operator[](int index) const {
require(index >= 0,
"PStash::operator[] index negative");
if(index >= next)
return 0; // To indicate the end
require(storage[index] != 0,
"PStash::operator[] returned null pointer");
return storage[index];
}
template<class T, int incr>
T* PStash<T, incr>::remove(int index) {
// operator[] performs validity checks:
T* v = operator[](index);
// "Remove" the pointer:
storage[index] = 0;
return v;
}
template<class T, int incr>
void PStash<T, incr>::inflate(int increase) {
const int tsz = sizeof(T*);
T** st = new T*[quantity + increase];
memset(st, 0, (quantity + increase) * tsz);
memcpy(st, storage, quantity * tsz);
quantity += increase;
delete []storage; // Old storage
storage = st; // Point to new memory
}
#endif // TPSTASH2_H ///:~
析构函数对于所有被包含的指针调用delete,并且因为类型由模型获取,所以
将发生适当的销毁
PStash::iterator遵循迭代器在其生命期内只结合单个容器对象这一模式
代码按照标准C++库容器方式,被用来创建终止哨兵
第二构造函数,容器的end()成员函数和用于比较operator==与operator!=
创建和测试两个不同种类的Stash对象:一个名为Int的新类,它宣布它的
构造和析构,另一个存放标准库string类的对象
//: C16:TPStash2Test.cpp
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#include "TPStash2.h"
#include "../require.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Int {
int i;
public:
Int(int ii = 0) : i(ii) {
cout << ">" << i << ' ';
}
~Int() { cout << "~" << i << ' '; }
operator int() const { return i; }
friend ostream&
operator<<(ostream& os, const Int& x) {
return os << "Int: " << x.i;
}
friend ostream&
operator<<(ostream& os, const Int* x) {
return os << "Int: " << x->i;
}
};
int main() {
{ // To force destructor call
PStash<Int> ints;
for(int i = 0; i < 30; i++)
ints.add(new Int(i));
cout << endl;
PStash<Int>::iterator it = ints.begin();
it += 5;
PStash<Int>::iterator it2 = it + 10;
for(; it != it2; it++)
delete it.remove(); // Default removal
cout << endl;
for(it = ints.begin();it != ints.end();it++)
if(*it) // Remove() causes "holes"
cout << *it << endl;
} // "ints" destructor called here
cout << "\n-------------------\n";
ifstream in("TPStash2Test.cpp");
assure(in, "TPStash2Test.cpp");
// Instantiate for String:
PStash<string> strings;
string line;
while(getline(in, line))
strings.add(new string(line));
PStash<string>::iterator sit = strings.begin();
for(; sit != strings.end(); sit++)
cout << **sit << endl;
sit = strings.begin();
int n = 26;
sit += n;
for(; sit != strings.end(); sit++)
cout << n++ << ": " << **sit << endl;
getchar();
} ///:~
为了方便,Int有一个相关的ostream operator<< , 用于Int& 和 Int*
在mian()中的第一个代码段用花括号括起来,用来强迫PStash<Int>的销毁,
并因而由析构函数自动清除
对于PStash的这两个实例,创建一个迭代器并用于遍历容器
输出 要把TPStash2Test.cpp放到工程目录下
>0 >1 >2 >3 >4 >5 >6 >7 >8 >9 >10 >11 >12 >13 >14 >15 >16 >17 >18 >19 >20 >21 >22 >23 >24 >25 >26 >27 >28 >29
~5 ~6 ~7 ~8 ~9 ~10 ~11 ~12 ~13 ~14
Int: 0
Int: 1
Int: 2
Int: 3
Int: 4
Int: 15
Int: 16
Int: 17
Int: 18
Int: 19
Int: 20
Int: 21
Int: 22
Int: 23
Int: 24
Int: 25
Int: 26
Int: 27
Int: 28
Int: 29
~0 ~1 ~2 ~3 ~4 ~15 ~16 ~17 ~18 ~19 ~20 ~21 ~22 ~23 ~24 ~25 ~26 ~27 ~28 ~29
-------------------
//: C16:TPStash2Test.cpp
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#include "TPStash2.h"
#include "../require.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Int {
int i;
public:
Int(int ii = 0) : i(ii) {
cout << ">" << i << ' ';
}
~Int() { cout << "~" << i << ' '; }
operator int() const { return i; }
friend ostream&
operator<<(ostream& os, const Int& x) {
return os << "Int: " << x.i;
}
friend ostream&
operator<<(ostream& os, const Int* x) {
return os << "Int: " << x->i;
}
};
int main() {
{ // To force destructor call
PStash<Int> ints;
for(int i = 0; i < 30; i++)
ints.add(new Int(i));
cout << endl;
PStash<Int>::iterator it = ints.begin();
it += 5;
PStash<Int>::iterator it2 = it + 10;
for(; it != it2; it++)
delete it.remove(); // Default removal
cout << endl;
for(it = ints.begin();it != ints.end();it++)
if(*it) // Remove() causes "holes"
cout << *it << endl;
} // "ints" destructor called here
cout << "\n-------------------\n";
ifstream in("TPStash2Test.cpp");
assure(in, "TPStash2Test.cpp");
// Instantiate for String:
PStash<string> strings;
string line;
while(getline(in, line))
strings.add(new string(line));
PStash<string>::iterator sit = strings.begin();
for(; sit != strings.end(); sit++)
cout << **sit << endl;
sit = strings.begin();
int n = 26;
sit += n;
for(; sit != strings.end(); sit++)
cout << n++ << ": " << **sit << endl;
getchar();
} ///:~
26: return os << "Int: " << x->i;
27: }
28: };
29:
30: int main() {
31: { // To force destructor call
32: PStash<Int> ints;
33: for(int i = 0; i < 30; i++)
34: ints.add(new Int(i));
35: cout << endl;
36: PStash<Int>::iterator it = ints.begin();
37: it += 5;
38: PStash<Int>::iterator it2 = it + 10;
39: for(; it != it2; it++)
40: delete it.remove(); // Default removal
41: cout << endl;
42: for(it = ints.begin();it != ints.end();it++)
43: if(*it) // Remove() causes "holes"
44: cout << *it << endl;
45: } // "ints" destructor called here
46: cout << "\n-------------------\n";
47: ifstream in("TPStash2Test.cpp");
48: assure(in, "TPStash2Test.cpp");
49: // Instantiate for String:
50: PStash<string> strings;
51: string line;
52: while(getline(in, line))
53: strings.add(new string(line));
54: PStash<string>::iterator sit = strings.begin();
55: for(; sit != strings.end(); sit++)
56: cout << **sit << endl;
57: sit = strings.begin();
58: int n = 26;
59: sit += n;
60: for(; sit != strings.end(); sit++)
61: cout << n++ << ": " << **sit << endl;
62: getchar();
63: } ///:~