Custom iterator: how do I keep track of it? - c++

I have this situation:
I have a class which keeps track of an array of pointers. I built a custom iterator which loops through this array.
My problem is on how to make it threadsafe, especially while incrementing/decrementing?
Here is a draft of the relevant parts of what I have:
typedef fruit * iterator;
class fruits
{
private:
fruit ** flist;
int n; //keeps track of position in flist
int count; //number of fruits
public:
iterator begin() {n=0; return fruit[n];}
iterator end() {n=count; return fruit[n];}
iterator operator++ ()
{
return fruit[++n];
}
}
The problem i see is that if two parts of the program create an iterator things won't work. How does C++ STL deal with it?
UPDATE: I have found the error of my ways. The iterator should keep track of where it is by itself. For that I created an iterator class embedded in my main class. Life is now good.

The standard containers maintain their iteration state in iterator objects separately from the container, so there can be multiple iterations over the container at the same time. So begin() and end() return iterators, but don't change the state of the container; operator++ acts on iterators, not the container. For a simple array like this, a pointer (to a fruit*, not a fruit) works perfectly well as an iterator, so you can just define begin() and end():
iterator begin() {return flist;}
iterator end() {return flist + count;}
and use it like this:
for (iterator i = my_fruit.begin(); i != my_fruit.end(); ++i)
do_something_with(*i); // *i is a fruit*
There's no problem with multiple threads doing this at the same time, as long as none of them try to modify the container.
On the other hand, unless this is a learning exercise to better understand how containers and iterators work, you're much better off using std::vector than implementing your own version of it.

Related

Should I write iterators for a class that is just a wrapper of a vector?

Should I write iterators for a class that is just a wrapper of a vector?
The only private member of my class called Record is a vector.
I want to be able to do this:
for (auto& elem : record) {
// do something with elem
}
where record is of type Record. To do this I need to implement iterators
for the Record class. But, I can also do this:
for (auto& elem : record.elems) {
// do something with elem
}
where record.elems is the vector I mentioned. But this way
I will need to make it public.
Another approach is:
for (auto& elem : record.getElems()) {
// do something with elem
}
this way I get iteration, and the member stays private.
Probably this is the best way to go.
My main question is, why would I bother to implement iterators for the Record class
when it is just a wrapper for a vector? My colleague insists I implement iterators,
and he can't even explain me why, it is just stupid.
Implementing iterators will help the encapsulation of your class. If at any point in time, you decide to replace the backing vector with another data type, you might break dependencies.
Actually, you do not need to implement the iterator. You can typedef your iterators to be the vector iterators and create inline begin() and end() methods to return the vector's iterators.
EDIT: As requested a simple example:
template <class T>
class vectorWrapper
{
typedef typename std::vector<T> backingType;
backingType v;
public:
typedef typename backingType::iterator iterator;
typedef typename backingType::const_iterator const_iterator;
iterator begin() { return v.begin(); }
const_iterator begin() const { return v.begin(); }
const_iterator cbegin() const { return v.cbegin(); } // C++11
iterator end() { return v.end(); }
const_iterator end() const { return v.end(); }
const_iterator cend() const { return v.cend(); } // C++11
};
If needed (or wanted) reverse_iterators can be added the same way. Since the methods are likely to be inlined by the compiler, there is little to no overhead in using this.
If your class should look a range, you are best off to provide access to iterators via begin() and end() members. The key advantage is that objects of the class can be used consistent with other ranges: there isn't much doubt of how the class is meant to use and the effort is small: unless you don't expect your class to be used, you should make it as easy and obvious to use. Of course, if you don't expect you class to be used why bother writing it in the first place?
Whether these need to have a different type than those of the vector depends on whether you need to impose any constraints. If the class does 't impose constraints on the elements or on their order it is sufficient to pass on the iterators. Otherwise it may be necessary to create custom iterators.

How to check if simple C++ standard library iterator can be advanced?

Suppose I have a class encapsulating std container:
class Stash
{
list<int> Data;
public:
list<int>::const_iterator GetAccess() const { return Data.begin(); }
};
It's very convenient way of forcing the user to read the data in form of the iterator. However, I can't find the way other that comparing the iterator to container.end(). So, I would like to know if there's an option to do it solely by stdlib or I have to write iterator class myself (with can_advance method, for example).
Relevant question might be this one, but it asks whether the iterator is valid, not whether it can advance. I weren't able to find any information about the latter.
You can't do this, a single iterator does not contain the information when it is at the end of the sequence its pointing into.
Normally, this is solved by either providing a range (think std::make_pair(cont.begin(), cont.end())), or providing begin() and end() methods to your class, effectively making it a range.
Iterators work in pairs: an iterator that points to the beginning of a sequence and an iterator that points past the end of the sequence. That's why all the containers have begin() and end() member functions: so you can look at the sequence of values that the container manages.
It would be far more idiomatic to change the name of GetAccess to begin and to add end. Having end() would also make it possible to apply standard algorithms to the data.
What you seem to be asking for is a "lookahead" iterator. You could write a class to "adapt" an iterator to have lookahead, where the adaptor just stays one step ahead of your code:
template<class FwdIter>
class lookahead_iterator
{
public:
lookahead_iterator(const FwdIter& begin): cur_iter(begin), next_iter(++begin) {}
operator FwdIter() const { return cur_iter; }
lookahead_iterator<FwdIter>& operator ++() { cur_iter = next_iter++; return *this; }
// Other methods as needed.
private:
FwdIter cur_iter;
FwdIter next_iter;
};
Needless to say, this gets a lot more complicated if you need more than a forward iterator.

Implementing state-machines (ala generators) using iterators

Lately I have been needing to implement small classes that generate a bunch of numbers. It would be very convenient if C++ had generators like python, but unfortunately it is not so.
So I have been thinking of how to best implement these types of objects, for easy iteration and composition. When we think of iterators over containers, they essentially only hold the index to an element, and the bulk of the information is in the container itself. This allows for several iterators to be referencing different elements within a collection at the same time.
When it come to state machines, it becomes apparent that the iterator will have to hold the whole state as several iterators need to be able to be independent. In that sense, the state machine class is more of a "builder" of these iterators which are the actual state machines.
As a toy example I have implemented the range generator (ala xrange in python), that can be used in loops:
// using range-for from c++11
for (auto i : range<int>(1, 30)) {
cout << i << endl;
}
The code can be found on my bitbucket.
That said, it is awkward to store the whole state within the iterator, since the end() iterator is created just for the sake of comparing the ending state, which wastes space if the state is a large collection of members.
Has there been anything done with simple linear state machines, and looping over them with iterators?
If you support only forward iteration, you might be able to get away with using a different type for end() then for begin(). Here's the basic idea
class iterator;
class iterator_end {
typedef ... value_type;
...
iterator& operator++ () { throw ... }
value_type operator* () { throw ... }
bool operator== (const iterator& e) const { return e == *this; }
}
class iterator {
typedef ... value_type;
..
iterator& operator++ () { ... }
value_type operator* () { ... }
bool operator== (const iterator_end& e) const { return are_we_done_yet }
}
class statemachine {
iterator begin() const { ... }
iterator_end end() const { ... }
}
I've never tries this though, so I can't guarantee that this will work. Your state-machine's iterator and const_iterator typedefs will specify a different type than end() returns, which may or may not cause trouble.
Another possibility is to go with a variation on pimpl which uses boost::optional. Put the iterator state into a separate class, and store it within a boost::optional within the iterator. Leave the state unset for the iterator returned by end(). You won't save any memory, but you avoid heap allocations (boost::optional doesn't do any, it uses placement new!) and initialization overhead.

Hybrid vector/list container?

I'm in need of a container that has the properties of both a vector and a list. I need fast random access to elements within the container, but I also need to be able to remove elements in the middle of the container without moving the other elements. I also need to be able to iterate over all elements in the container, and see at a glance (without iteration) how many elements are in the container.
After some thought, I've figured out how I could create such a container, using a vector as the base container, and wrapping the actual stored data within a struct that also contained fields to record whether the element was valid, and pointers to the next/previous valid element in the vector. Combined with some overloading and such, it sounds like it should be fairly transparent and fulfill my requirements.
But before I actually work on creating yet another container, I'm curious if anyone knows of an existing library that implements this very thing? I'd rather use something that works than spend time debugging a custom implementation. I've looked through the Boost library (which I'm already using), but haven't found this in there.
If the order does not matter, I would just use a hash table mapping integers to pointers. std::tr1::unordered_map<int, T *> (or std::unordered_map<int, unique_ptr<T>> if C++0x is OK).
The hash table's elements can move around which is why you need to use a pointer, but it will support very fast insertion / lookup / deletion. Iteration is fast too, but the elements will come out in an indeterminate order.
Alternatively, I think you can implement your own idea as a very simple combination of a std::vector and a std::list. Just maintain both a list<T> my_list and a vector<list<T>::iterator> my_vector. To add an object, push it onto the back of my_list and then push its iterator onto my_vector. (Set an iterator to my_list.end() and decrement it to get the iterator for the last element.) To lookup, look up in the vector and just dereference the iterator. To delete, remove from the list (which you can do by iterator) and set the location in the vector to my_list.end().
std::list guarantees the elements within will not move when you delete them.
[update]
I am feeling motivated. First pass at an implementation:
#include <vector>
#include <list>
template <typename T>
class NairouList {
public:
typedef std::list<T> list_t;
typedef typename list_t::iterator iterator;
typedef std::vector<iterator> vector_t;
NairouList() : my_size(0)
{ }
void push_back(const T &elt) {
my_list.push_back(elt);
iterator i = my_list.end();
--i;
my_vector.push_back(i);
++my_size;
}
T &operator[](typename vector_t::size_type n) {
if (my_vector[n] == my_list.end())
throw "Dave's not here, man";
return *(my_vector[n]);
}
void remove(typename vector_t::size_type n) {
my_list.erase(my_vector[n]);
my_vector[n] = my_list.end();
--my_size;
}
size_t size() const {
return my_size;
}
iterator begin() {
return my_list.begin();
}
iterator end() {
return my_list.end();
}
private:
list_t my_list;
vector_t my_vector;
size_t my_size;
};
It is missing some Quality of Implementation touches... Like, you probably want more error checking (what if I delete the same element twice?) and maybe some const versions of operator[], begin(), end(). But it's a start.
That said, for "a few thousand" elements a map will likely serve at least as well. A good rule of thumb is "Never optimize anything until your profiler tells you to".
Looks like you might be wanting a std::deque. Removing an element is not as efficient as a std::list, but because deque's are typically created by using non-contiguous memory "blocks" that are managed via an additional pointer array/vector internal to the container (each "block" would be an array of N elements), removal of an element inside of a deque does not cause the same re-shuffling operation that you would see with a vector.
Edit: On second though, and after reviewing some of the comments, while I think a std::deque could work, I think a std::map or std::unordered_map will actually be better for you since it will allow the array-syntax indexing you want, yet give you fast removal of elements as well.

STL iterator as return value

I have class A, that contains std::vector and I would like to give an access to the vector from outside class A.
The first thing that came to my mind is to make a get function that returns iterator to the vector, but walk through the vector I will need two iterators (begin and end).
I was wondering is there any way (technique or patters) to iterate whole vector with only one iterator? Or maybe some other way to get access to vector, of course without using vector as return value :)
Why not add both a begin() and end() function to your class that simply return v.begin(); and return v.end();? (Assuming v is your vector.)
class MyVectorWrapper
{
public:
// Give yourself the freedom to change underlying types later on:
typedef vector<int>::const_iterator const_iterator;
// Since you only want to read, only provide the const versions of begin/end:
const_iterator begin() const { return v.begin(); }
const_iterator end() const { return v.end(); }
private:
// the underlying vector:
vector<int> v;
}
Then you could iterate through your class like any other:
MyVectorWrapper myV;
for (MyVectorWrapper::const_iterator iter = myV.begin(); iter != myV.end(); ++i)
{
// do something with iter:
}
It seems potentially unwise to give that much access to the vector, but if you're going to why not just return a pointer or reference to the vector? (Returning the vector itself is going to be potentially expensive.) Alternately, return a std::pair<> of iterators.
An iterator is just an indicator for one object; for example, a pointer can be a perfectly good random-access iterator. It doesn't carry information about what sort of container the object is in.
The STL introduced the idiom of using two iterators for describing a range. Since then begin() and end() are the getters. The advantage of this is that a simple pair of pointers into a C array can be used as perfect iterators. The disadvantage is that you need to carry around two objects. C++1x will, AFAIK, introduce a range concept to somewhat ease the latter.
It sounds like what you need to accomplish will be potential violation of the so called Law of Demeter. This law is often an overkill, but oftentimes it is reasonable to obey it. Although you may grant read-only access by giving out only const-iterators you are still at risk that your iterators will get invalidated (easily with vectors) without third party knowing it. As you can never predict how your program will evolve over-time it is better to avoid providing features that can be misused.
Common motto: make your class interface easy to use and hard to misuse. The second part is important for overall product quality.
More:
template <typename T,typename A = std::allocator<T>>
class yetAnotherVector
{
public:
typedef std::_Vector_iterator<T, A> iterator;
protected:
std::vector<T,A> mV;
public:
void add(const T& t)
{
if(!isExist(t))mV.push_back(t);
}
bool isExist(const T& t)
{
std::vector<T,A>::iterator itr;
for(itr = mV.begin(); itr != mV.end(); ++itr)
{
if((*itr) == t)
{
return true;
}
}
return false;
}
iterator begin(void){return mV.begin();}
iterator end(void){return mV.end();}
};