C and C++ Programming Resources

Custom Search

Generic containers

A plethora of iterators

As mentioned earlier an iterator is an abstraction that allows code to be generic, that is, to work with different types of containers without knowing the underlying structure of those containers. Most containers support iterators . You can always say:

<ContainerType>::iterator
<ContainerType>::const_iterator

to produce the types of the iterators produced by that container. Every container has a begin( ) member function that produces an iterator indicating the beginning of the elements in the container, and an end( ) member function that produces an iterator which is the as the past-the-end marker of the container. If the container is const? begin( ) and end( ) produce const iterators, which disallow changing the elements pointed to (because the appropriate operators are const).

All iterators can advance within their sequence (via operator++) and allow == and != comparisons. Thus, to move an iterator it forward without running it off the end, you say something like:

while(it != pastEnd) {
// Do something
it++;
}

in which pastEnd is the past-the-end marker produced by the container?s end( ) member function.
An iterator can be used to produce the element that it is currently selecting within a container through the dereferencing operator (operator*). This can take two forms. If it is an iterator and f( ) is a member function of the objects held in the container that the iterator is pointing within, you can say either:

(*it).f();

or

it->f();

Knowing this, you can create a template that works with any container. Here, the apply( ) function template calls a member function for every object in the container, using a pointer to member that is passed as an argument:

//: C07:Apply.cpp
// Using simple iteration
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;

template<class Cont, class PtrMemFun>
void apply(Cont& c, PtrMemFun f) {
typename Cont::iterator it = c.begin();
while(it != c.end()) {
((*it).*f)(); // Alternate form
it++;
}
}

class Z {
int i;
public:
Z(int ii) : i(ii) {}
void g() { i++; }
friend ostream&
operator<<(ostream& os, const Z& z) {
return os << z.i;
}
};

int main() {
ostream_iterator<Z> out(cout, " ");
vector<Z> vz;
for(int i = 0; i < 10; i++)
vz.push_back(Z(i));
copy(vz.begin(), vz.end(), out);
cout << endl;
apply(vz, &Z::g);
copy(vz.begin(), vz.end(), out);
} ///:~

You can?t use operator-> in this case, because the resulting statement would be
(it->*f)();

which attempts to use the iterator?s operator->*, which is not provided by the iterator classes .
It is much easier to use either for_each( ) or transform( ) to apply functions to sequences anyway.

Pages: [Page - 1] [Page - 2] [Page - 3] [Page - 4] [Page - 5] [Page - 6] [Page - 7] [Page - 8] [Page - 9] [Page - 10] [Page - 11] [Page - 12] [Page - 13]

Tags: , ,

There are 1 Comment to this post. You can follow any responses to this entry through the RSS 2.0 feed. You can skip to the end and leave a response or TrackBack from your own site.

  • Jimson says:

    Sorry to disappoint you, but this is actually bull. STL containers are not meant to be used as base classes. There are no virtual functions to overwrite, so you can’t alter the functionality. Data members are private, so no luck there either – these two points are make container inheritance questionable, but the fact that no virtual destructor is offered makes it just plain wrong. Deleting a derived class via a pointer to the container base class will result in undefined behaviour.

    If you want to add data members, just use composition. If you want to add functionality, write a new algorithm, but don’t inherit from STL containers.

    You might want to look this issue up, the internet is actually full of advice on this, as many novice STL users make this mistake…


Leave a Reply

You must be logged in to post a comment.