The STL+ C++ Library Collection
Iterators in the STL are badly designed - there are several major pitfalls with using them as a result of their design. However, I wanted STLplus to feel like the STL to make it easier to use, so felt I should use the iterator concept despite the problems associated with them. Some of the STLplus components therefore also use iterators.
In STLplus 2 I included some error checking for misuse of iterators. In STLplus 3 I have completed the job - so I have termed the STLplus iterators "safe iterators".
The following STLplus classes use iterators, all of them based on the safe_iterator class:
Here is the user interface to the safe_iterator class:
template<typename O, typename N>
class stlplus::safe_iterator
{
public:
// construct a null iterator
safe_iterator(void) throw();
// construct a valid iterator from the owner node's master iterator
safe_iterator(const master_iterator<O,N>&) throw();
// comparison - do they point to the same element?
bool operator ==(const safe_iterator<O,N>& right) const throw();
bool operator !=(const safe_iterator<O,N>& right) const throw();
// The < operator is used for putting iterators into sets
bool operator <(const safe_iterator<O,N>& right) const throw();
// dereference
N& operator*(void) const throw(null_dereference,end_dereference);
N* operator->(void) const throw(null_dereference,end_dereference);
// a null iterator is one that has not been initialised with a value yet
// i.e. you just declared it but didn't assign to it
bool null(void) const throw();
// an end iterator is one that points to the end element of the list of nodes
// in STL conventions this is one past the last valid element and must not be dereferenced
bool end(void) const throw();
// a valid iterator is one that can be dereferenced
// i.e. non-null and non-end
bool valid(void) const throw();
// called by the owner class to check the rules
void assert_valid(const O* owner) const throw(wrong_object,null_dereference,end_dereference);
};
The void constructor ensures that an unassigned iterator is classified as a null iterator.
The second iterator is used internally by the container object to create a valid iterator.
Built-in comparison operators allow for comparisons, for example to test for the end condition in a for loop or any other conditional. They also allow iterators to be added to sets (the < operator) and hashes (the == operator).
The dereference operators are only legal on valid iterators - any attempt to dereference a null or end iterator will throw an exception.
The methods null(), end() and valid() allow the programmer to test the validity of an iterator before dereferencing it.
The assert_valid method is called by the owning container to check that the iterator belongs to it before using it. If not, it will throw the wrong_object exception. Also, if the owner needs to dereference the iterator, it will check whether it is valid and if not, throw either the null_dereference or end_dereference exception.