10

I've written my own container template with an iterator. How do I implement const_iterator?

template <class T> class my_container { private: ... public: my_container() : ... { } ~my_container() { } class iterator : public std::iterator<std::bidirectional_iterator_tag, T> { public: ... 

3 Answers 3

5

The only difference should be that when you de-reference a const iterator you get a const reference rather than a reference to the object in the container.

Sign up to request clarification or add additional context in comments.

4 Comments

What about methods that take iterators as arguments or return iterators? I have to overload them for const_iterators? Seems like a bunch of repeated code.
iterators should be convertible into const_iterators, so you won't have to overload if you only need a const_iterator. You do for functions like begin(), end(), but there's no way around that, as const also part of the method's signature.
@ Posco Grubb: No. If you have methods that take iterators then template's them. The method should work for anything that acts like an iterator. If the method requires an iterator rather than a const_iterator the compiler will generate the appropriate error.
also, add a templated converting constructor to const_iterator that takes a iterator. Then you can conveniently convert from a non-const to a const_iterator
3

I find the easiest way to implement iterators is boost::iterator. If you want to roll your own, I think the signature should be:

class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const T> { 

with the implementation the same (assuming you are using reference_type and so forth in your function signatures)

6 Comments

I was surprised to find that iterator_traits<vector<int>::const_iterator>::value_type is int, not int const (T, instead of const T in your code). I think with const makes more sense though. However, bottom-line is if you want to match up with the standard containers, you need to use non-const T.
The important thing with a const iterator is that you can't use it to change the collection being iterated over. So, T or const T& are appropriate. Using const with just T isn't necessary (since the return will be a copy)
Well, if you want to specify that by-value is non-const, you have to specify all the parameters: class const_iterator : public std::iterator<std::bidirectional_iterator_tag, T, ptrdiff_t, const T*, const T&>. I would go with brevity (with some added protection against assignment/equality bugs) rather than conformity with STL vector, but it is a tough choice from a design standpoint.
I would also prefer a non-const T. So that functions that return value_type return a non-const one (so move constructors could be written and are effective). Also, compilers could warn if such a function like Iter::value_type f(Iter b, Iter e); is generated (there are no const rvalues of non-class type).
Hm wow. A lot of things I had not considered. What I wanted is an iterator such that the value (T) cannot be changed while the container being iterated over (my_container) can be changed. I also wanted compatibility with STL, but if I understand the above comments correctly, an STL const_iterator is the opposite: it allows modifying the object contained, and disallows modifying the container.
|
0

Roger Pate, value_types are "simple". I suspect you'll see the const if you look at iterator_traits::const_iterator>::reference, which I think will be "const int&".

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.