Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
In Stlshape.cpp, the pointers did not clean
themselves up automatically. It would be convenient to be able to do this
easily, rather than writing out the code each time. Here is a function template
that will clean up the pointers in any sequence container. Note that it is
placed in the book s root directory for easy access:
//: :purge.h
// Delete pointers in an STL sequence container.
#ifndef PURGE_H
#define PURGE_H
#include <algorithm>
template<class Seq> void purge(Seq& c) {
typename Seq::iterator i;
for(i = c.begin(); i != c.end(); ++i) {
delete *i;
*i = 0;
}
}
// Iterator version:
template<class InpIt> void purge(InpIt begin,
InpIt end) {
while(begin != end) {
delete *begin;
*begin = 0;
++begin;
}
}
#endif // PURGE_H ///:~
In the first version of purge( ), note that typename
is absolutely necessary. This is exactly the case that keyword was designed to
solve: Seq is a template argument, and iterator is something that
is nested within that template. So what does Seq::iterator refer to? The
typename keyword specifies that it refers to a type, and not something
else.
Although the container version of purge( ) must
work with an STL-style container, the iterator version of purge( )
will work with any range, including an array.
Here is a rewrite of Stlshape.cpp, modified to use
the purge( ) function:
//: C07:Stlshape2.cpp
// Stlshape.cpp with the purge() function.
#include <iostream>
#include <vector>
#include "../purge.h"
using namespace std;
class Shape {
public:
virtual void draw() = 0;
virtual ~Shape() {};
};
class Circle : public Shape {
public:
void draw() { cout << "Circle::draw
<< endl; }
~Circle() { cout << "~Circle <<
endl; }
};
class Triangle : public Shape {
public:
void draw() { cout << "Triangle::draw
<< endl; }
~Triangle() { cout << "~Triangle <<
endl; }
};
class Square : public Shape {
public:
void draw() { cout << "Square::draw
<< endl; }
~Square() { cout << "~Square <<
endl; }
};
int main() {
typedef std::vector<Shape*> Container;
typedef Container::iterator Iter;
Container shapes;
shapes.push_back(new Circle);
shapes.push_back(new Square);
shapes.push_back(new Triangle);
for(Iter i = shapes.begin(); i != shapes.end(); i++)
(*i)->draw();
purge(shapes);
} ///:~
When using purge( ), carefully consider
ownership issues. If an object pointer is held in more than one container, be
sure not to delete it twice, and you don t want to destroy the object in the
first container before the second one is finished with it. Purging the same
container twice is not a problem because purge( ) sets the pointer
to zero once it deletes that pointer, and calling delete for a zero
pointer is a safe operation.
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |