Custom nested class iterator for STL data structure - c++

#pragma once
#include <memory>
#include <vector>
#include <random>
#include <list>
class City;
class MemberReport;
class CityReport
{
private:
City* mCity;
protected:
static const int BinSize = 7;
class ReportsBin {
public:
std::shared_ptr<MemberReport> mReports[BinSize+1];
bool IsFull();
void Add(std::shared_ptr<MemberReport> report);
};
std::list<std::shared_ptr<ReportsBin>> mReportBins;
public:
explicit CityReport(City* city);
void Add(std::shared_ptr<MemberReport> report);
class Iter
{
public:
Iter(CityReport *cityReport, int pos1, int pos2) : mCityReport(cityReport), mPos1(pos1), mPos2(pos2) {}
bool operator!=(const Iter &other) const
{
return mPos1 != other.mPos1 || mPos2 != other.mPos2;
}
std::shared_ptr<MemberReport> operator *() const { return mCityReport->mReportBins[mPos1][mPos2]; }
const Iter& operator++()
{
mPos1++;
mPos2++;
return *this;
}
private:
CityReport *mCityReport;
int mPos1;
int mPos2;
};
Iter begin() { return Iter(this, 0, 0); }
Iter end() { return Iter(this, 0, 0); }
};
So I'm trying to create a custom iterator class for the class above however, I'm having trouble with the operator* and the operator++ due to the return type being stored in the form of a singly linked list inside of a list of shared pointers.
So I tried having the first parameter of the iterator constructor being ReportsBin* reportsBin although that didn't work since I need to return type std::shared_ptr<MemberReport> in the operator*. Now, I have it as CityReport* cityReport so that I can access the list of shared pointers mReportBins eventually leading to mReports. The problem is when I do mCityReport->mReportBins[mPos1][mPos2] to access mReports, I am not able to do so since you can't access lists using indices. My only other idea is to create an iterator within the operator* to iterate over the list of shared pointers of type std::list<std::shared_ptr<ReportsBin>> but I feel as though that defeats the whole purpose of the iterator class. I can't modify the CityReport class either, I can only work with the iterator class at hand.

I think using int for mPos1 is a mistake.
An iterator would be a better type in most situations. Unfortunately you make mReportBins accessible (as it is protected and not private) so depending on how you use it maybe int is better. But for argument’s sake; let's use an iterator.
While we are at it may as well use an iterator for mPos2 as it will make the logic easier (though you can use int and swap checks for end against checks against the size of the array without any major difference.
Let's address the ReportsBin type first:
class ReportsBin {
public:
// Rather than using a C-Array
// Upgrade to a std::array this makes it easier using some types.
using ReportsCont = std::array<std::shared_ptr<MemberReport>, BinSize+1>;
// We may not be upgrading this to full container status.
// But lets make accessing the members container here easier by
// providing some simple iterator accesses to the memebers.
using iterator = ReportsCont::iterator;
ReportsCont mReports;
iterator begin() {return std::begin(mReports);}
iterator end() {return std::end(mReports);}
bool IsFull();
void Add(std::shared_ptr<MemberReport> report);
};
Next lets address the container you are using to store the ReportBin. You use a std::list and I am fine with theat. But lets make accessing the type information easier by using a couple of using directives.
using Container = std::list<std::shared_ptr<ReportsBin>>;
using ContainerIter = Container::iterator;
Container mReportBins;
Now we can define the member of Iter in terms of the types we have defined that makes it easy to read and easy to modify in a single place.
class Iter // More traditionally this should be iterator
{
// STUFF
..
private:
CityReport* mCityReport;
ContainerIter mPos1;
ReportsBin::iterator mPos2;
};
This makes our dereference operator trivial.
std::shared_ptr<MemberReport> operator*() const
{
return *mPos2;
}
Constructor:
You only ever used the constructor to the first element. So why force this user to provide those 0,0. Let's remove that. Let's also not pass around raw pointers unless we really have to, so make the parameter a CityReport& so that users know it can never be null it always refers to something.
Iter(CityReport& cityReport, ContainerIter p1)
: mCityReport(&cityReport) // convert to pointer here
// Allows copying.
, mPos1(p1)
{
// We can only set mPos2 if mPos1 is dereferancable.
if (mPos1 != mCityReport->mReportBins.end()) {
mPos2 = (*mPos1)->mReports.begin();
}
}
Like the constructor, you need to take special care of the test for situations where mPos1 is no longer dereference as mPos2 is no longer valid in a test. So the comparison becomes a little more complex:
bool operator==(const Iter &other) const
{
auto end = mCityReport->mReportBins.end();
// If mPos1 and other.mPos1 are both at the end.
// then the value of mPos2 have no meaning, so don't compare.
return (mPos1 == end && other.mPos1 == end)
// Otherwise, make sure both iterators are the same.
|| (mPos1 == other.mPos1 && mPos2 == other.mPos2);
}
// Usually good to define both == and != and define them in
// terms of each other for consistency.
bool operator!=(const Iter &other) const {return !(*this == other);}
This leaves the increment:
Your increment looks strange. If you want to move diagonally across the array that seems fine. But you don't make a check to make sure the two containers are square with each other. So it looks wrong. So I have taken the liberty of redefining the increment so it goes across all elements.
const Iter& operator++()
{
// Increment mPos2 to the next element.
// Note this is fine without a test.
// It is illegal to call operator++ on an iterator where
// mPos1 is at the end.
++mPos2;
// If we reach the end of its container
// Then we need to do some extra work to move to the next
// container.
if (mPos2 == (*mPos1)->mReports.end()) {
// Increment the outer iterator.
// If we are not at the end of the container
// reset mPos2
++mPos1;
if (mPos1 != mCityReport->mReportBins.end()) {
mPos2 = (*mPos1)->mReports.begin();
}
}
return *this;
}
Now lets define begin and end.
Iter begin() { return Iter(*this, this->mReportBins.begin()); }
Iter end() { return Iter(*this, this->mReportBins.end()); }
Lets address other things you should be thinking about.
You look like you want to make this a container.
To do that you need to define a few more helper types in the container type and support a couple of other standard functions.
There are a couple of different types of container:
https://en.cppreference.com/w/cpp/container
But the basics of what you "should" support are here:
https://en.cppreference.com/w/cpp/named_req/Container
Types your container should support:
// A typical container class will define these.
using value_type = T;
using reference = T&;
using const_reference = const T&;
using iterator = <Type of Your Iterator>;
using const_iterator = const iterator;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
// Note: You may have to customize these.
// Or explicitly not support them if that makes sense.
Your Iterator class should also define some (very similar types) types:
https://en.cppreference.com/w/cpp/iterator/iterator_traits
You can define an explicit instantiation of iterator_traits to get these types. But it is usually easier to define them in the iterator type itself.
using value_type = MemberReport;
using reference = MemberReport&;
using const_reference = const MemberReport&;
using iterator = MemberReport*;
using const_iterator = MemberReport const*;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;

Related

Stateful C++ Input Iterators post increment problem

I was implementing an iterator that takes another float values producing input iterator and returns true if a rising was detected. So, the iterator works effectively as a Software-ADC (Analog-Digital-Converter).
I've minimized the actual code to the following:
#include <iterator>
template<typename It>
struct ADCFilter
{
using iterator_tag = std::input_iterator_tag;
ADCFilter(const float threshold, It it)
: It_{it}, Threshold_{threshold}, LastAnalogVal_{0}
{}
bool operator*()
{
float analog_val = *It_;
// rising edge
if (analog_val >= Threshold_ && LastAnalogVal_< Threshold_)
{
LastAnalogVal_ = analog_val;
return true;
}
// no rising edge
LastAnalogVal_ = analog_val;
return false;
}
ADCFilter operator++() { ++It_; return *this; }
// Problem is here
ADCFilter operator++(int) {auto self = *this; operator++(); return self; }
private:
It It_;
float Threshold_;
float LastAnalogVal_;
};
As you can see I need to cache the last analog value.
And if somebody uses the iterator in such a way:
std::vector<float> v = {...};
auto f = ADCFilter(0.2f, v.begin());
while(true) {
std::cout << *f++; // <- post inc
}
The cached value is never stored as it's only present in the returned copy.
This problem doesn't occur though with pre increment because we are dereferencing the actual iterator and not a copy of it.
I could easily prohibit the usage of post increment operator by not implementing it, but according to https://en.cppreference.com/w/cpp/named_req/InputIterator it must be implemented for input iterators.
So, the question is how can I correctly implement a stateful input iterator that acts like a filter/mapper to another input iterator?
This can be done by reimplementing the operator so that its internal data holds just the bool value, instead of the floating point value from which the bool value is derived only when the iterator gets dereferenced.
In other words, the dereferencing iterator should simply be:
bool operator*() const // It should be const, by the way
{
return value;
}
// ...
private:
bool value;
The constructor initializes the value to false. All the code that's currently in the dereferencing operator gets basically moved into the operator++(), and its end result is an updated value. It is not necessary to hold a copy of the real value getting iterated over, the operator++ can simply compare the current value referenced by the wrapped iterator with the new value after the wrapped iterator gets incremented, and update the value.
The post-increment ++ operator remains unchanged.

create a Set template class using the Standard C++ Library vector as an underlying implementation

I just read a chapter on templates and iterators but this still is hard to understand. basically i want to create a Set template class that accepts only one of each type of object that you put into it, implemented using a vector.
Problem is, I don't know how to write the insert function in the Set class, and the constructor in the nested iterator class. Also, most of the functions I have provided are examples from the chapter in the text, I do not even know if they are necessary or I am doing it right. Comments? Because this is a very confusing one. Here is my code:
//testSetClass.cpp
#include <iostream>
#include <vector>
using namespace std;
/****************************CLASS DEFINITION*********************************/
// -----------------------------------------
// SET
// -----------------------------------------
template <class T>
class Set
{
vector<T> theSet;
public:
Set() {}
Set(const Set& s): theSet(s.theSet){} //copy constructor
~Set(){ theSet.clear(); }
void insert(T t)
{
//insert in orderly fashion? as set class does too
//also, how do i check for duplicates?
theSet.push_back(t);
}
//nested iterator class: that supports the begin() and end() sentinel
class iterator; //declaration
friend class iterator;
class iterator //definition
{
Set<T>& s;
int index;
public:
iterator(const Set<T>& ss): s(ss), index(0){}
//to create the "end sentinel" operator:
iterator(Set<T>& ss,bool):s(ss){} //???
T operator*() {return s.theSet.at(index);} //is this right?
T operator++() //prefix form
{
return ++s.theSet.at(index);
}
T operator++(int) //postfix form
{
return s.theSet.at(index)++;
}
bool operator!=(const iterator& ri)const {return index!=ri.index;}
};
//iterators begin() and end()
iterator begin()const { return iterator (*this); }
//create the end sentinel:
iterator end() { return iterator (*this,true); } //why?
};
/*************************************END OF CLASS DEFINITIONS*********************************/
/* *****************************************************************************
* MAIN
* *****************************************************************************
*
* REMARKS:
* to test that the class works correctly.
* *****************************************************************************/
int main (int argv, char const *argc[])
{
Set<int> other;
for(int i = 0; i<10; ++i)
other.insert(i);
for(Set<int>::iterator start = other.begin(); start != other.end(); start++)
cout<<*start<<endl;
cout << "\n\nProgram ends successfully!" <<endl;
}
Use std::vector<T>::iterator for your iterator. And similar for your const_iterator.
To find, use std::equal_range. If first==second, return end().
To insert, find. If it is already there, stop. If it isn't there, insert it. The lazy way to insert it is to push back, then sort. Do it the lazy way first.
Once you have done the above, you have a working Set<T>. Test it against std::set<T> with a bunch of data. Write a bunch of unit tests to make sure this Set<T> works just like std::set<T> with regards to duplicates, ordering, finding, etc.
Now make your Set<T> more efficient. Replace that Find with a call to lower_bound and <, and insert the element where it is supposed to be instead of insert-then-sort. (It is ok that this makes no sense to you; get a working Set before even reading this, then spend some time unpacking it).
Or, make a lazy-sort Set<T> that appends blindly, and only sorts exponentially rarely on insert. On read, it either sorts, or it examines the sorted part with a binary search and the remaining (small) part with a linear search. Or somesuch.
Another improvement would be to write a manual iterator like above; one that isn't invalidated as easily as a std::vector iterator. This is ... tricky to get right.
But work on efficiency after you have correctness.
//also, how do i check for duplicates?
With theSet.find()....
iterator(Set& ss,bool):s(ss){} //???
That's not going to work. Many options, easiest being to also set index to s.theSet.size() so the existing != will work.
T operator*() {return s.theSet.at(index);} //is this right?
Nope... you need to return a T& to - rather than a copy of - the vector's element.
operator++ / operator++(int)
You need to increment the iterator (i.e. index), not increment what the iterator addresses, and should return *this (with return type iterator&). Study some iterator implementations....
iterator end() { return iterator (*this,true); } //why?
Why what? Anyway, you'd ideally provide const versions of begin() and end() that return const_iterators (which would be pretty much like iterator but only expose const T&), as well as non-const versions returning iterators: you're mixing these two ideas, with iterator begin() const.

How can I build iterator for object that I have created in C++

I want to build a simple iterator, for example - in the class: "myVector":
#include <iostream>
using namespace std;
#define maxSize 10
class myVector {
private:
int *arr;
int sp;
public:
myVector() {
arr = new int[maxSize];
sp = 0;
}
bool add(int num) {
if (sp==maxSize) return 0;
arr[sp] = num;
sp++;
return 1;
}
};
in the Example - I built a class that produces objects of type myVector. Now I want to build iterator with an operator ++ to run on the private Array of the vector.
thank you very much
You must support std::iterator_traits<YourIterator>. The easy way is to inherit from std::iterator<?> with the appropiate arguments.
In doing so you have to decide on an iterator category. This determines what you guarantee to support, both operator wise and behaviour wise.
Now, boost has some helper types to make writing an iterator a tad easier. Consider using boost. But a basic iterator is not impossible to write without them.
In the particular case above, a pointer is a valid iterator for your problem. And easier than either of the above options. Use this as your first iteration: KISS. Note that pointers have std::iterator_traits support for free.
To make your object iterable (and support for(auto&&x:c) syntax), either write a free begin and end function in the same namespace as your class that produces iterators, or add begin() and end() methods that do the same. I tend to also add size and empty and front and back as I find them useful. As an example:
T& back(){return *std::prev(end());}
T const& back()const{return *std::prev(end());}
You need to write something like this.
class myVector {
class myIterator {
private:
int *position; //operator ++ increment this position
public:
myIterator operator++(){
//increment position here
}
int& operator*(){
//return *pos
}
bool operator==(const myIterator &it)const {
//check that pos and it.pos are the same
}
};
};
This will work but wont be a STL compliant iterator, for that you will also need to add several typedefs, to say for instance the type of your iterator (in your case you have an input iterator). If you want an STL iterator the easiest thing is to use boost facade iterator.

using base() to convert reverse_iterator to (forward) iterator [duplicate]

I have a class called Action, which is essentially a wrapper around a deque of Move objects.
Because I need to traverse the deque of Moves both forward and backwards, I have a forward iterator and a reverse_iterator as member variables of the class. The reason for this is becuase I need to know when I have gone one past the "end" of the deque, both when I am going forwards or backwards.
The class looks like this:
class Action
{
public:
SetMoves(std::deque<Move> & dmoves) { _moves = dmoves; }
void Advance();
bool Finished()
{
if( bForward )
return (currentfwd==_moves.end());
else
return (currentbck==_moves.rend());
}
private:
std::deque<Move> _moves;
std::deque<Move>::const_iterator currentfwd;
std::deque<Move>::const_reverse_iterator currentbck;
bool bForward;
};
The Advance function is as follows:
void Action::Advance
{
if( bForward)
currentfwd++;
else
currentbck++;
}
My problem is, I want to be able to retrieve an iterator to the current Move object, without needing to query whether I am going forwards or backwards. This means one function returning one type of iterator, but I have two types.
Should I forget returning an iterator, and return a const reference to a Move object instead?
Reverse iterators have a member base() which returns a corresponding forward iterator. Beware that this isn't an iterator that refers to the same object - it actually refers to the next object in the sequence. This is so that rbegin() corresponds with end() and rend() corresponds with begin().
So if you want to return an iterator, then you would do something like
std::deque<Move>::const_iterator Current() const
{
if (forward)
return currentfwd;
else
return (currentbck+1).base();
}
I would prefer to return a reference, though, and encapsulate all the iteration details inside the class.
This is exactly the sort of problem that prompted the design of STL to start with. There are real reasons for:Not storing iterators along with containersUsing algorithms that accept arbitrary iteratorsHaving algorithms evaluate an entire range instead of a single item at a time
I suspect what you're seeing right now is more or less the tip of the iceberg of the real problems. My advice would be to take a step back, and instead of asking about how to deal with the details of the design as it currently stands, ask a somewhat more general question about what you're trying to accomplish, and how best to accomplish that end result.
For those who care primarily about the question in the title, the answer is a heavily qualified "yes". In particular, a reverse_iterator has a base() member to do that. The qualifications are somewhat problematic though.
The demonstrate the problem, consider code like this:
#include <iostream>
#include <vector>
#include <iterator>
int main() {
int i[] = { 1, 2, 3, 4};
std::vector<int> numbers(i, i+4);
std::cout << *numbers.rbegin() << "\n";
std::cout << *numbers.rbegin().base() << "\n";
std::cout << *(numbers.rbegin()+1).base() << "\n";
std::cout << *numbers.rend() << "\n";
std::cout << *numbers.rend().base() << "\n";
std::cout << *(numbers.rend()+1).base() << "\n";
}
Running this at this particular moment on my particular machine produces the following output:
4
0
4
-1879048016
1
-1879048016
Summary: with rbegin() we must add one before converting to a forward iterator to get an iterator that's valid -- but with rend() we must not add one before converting to get a valid iterator.
As long as you're using X.rbegin() and X.rend() as the parameters to a generic algorithm, that's fine--but experience indicates that converting to forward iterators often leads to problems.
In the end, however, for the body of the question (as opposed to the title), the answer is pretty much as given above: the problem stems from trying to create an object that combines the collection with a couple of iterators into that collection. Fix that problem, and the whole business with forward and reverse iterators becomes moot.
Since std::deque is a random access container (same as std::vector) you are much better off using a single integer index into the deque for both traversals.
It seems to me that you actually have two different behavior in the same class.
Notably, it seems that you can only traverse your collection in one order, otherwise if you were to begin the traversal and then change the bforward argument you would end up with quite a strange situation.
Personally, I am all for exposing both iterators (ie, forward begin, end, rbegin and rend).
You could also return a simple Iterator object:
template <class T>
class Iterator
{
public:
typedef typename T::reference_type reference_type;
Iterator(T it, T end) : m_it(it), m_end(end) {}
operator bool() const { return m_it != m_end; }
reference_type operator*() const { return *m_it; }
Iterator& operator++() { ++m_it; return *this; }
private:
T m_it;
T m_end;
};
template <class T>
Iterator<T> make_iterator(T it, T end) { return Iterator<T>(it,end); }
Then, you can just return this simple object:
class Action
{
public:
Action(std::deque<Move> const& d): m_deque(d) {} // const& please
typedef Iterator< std::deque<Move>::iterator > forward_iterator_type;
typedef Iterator< std::deque<Move>::reverse_iterator > backward_iterator_type;
forward_iterator_type forward_iterator()
{
return make_iterator(m_deque.begin(), m_deque.end());
}
backward_iterator_type backward_iterator()
{
return make_iterator(m_deque.rbegin(), m_deque.rend());
}
private:
std::deque<Move> m_deque;
};
Or if you want to choose dynamically between forward and backward traversal, you could make Iterator a pure virtual interface and having both forward and backward traversal.
But really, I don't really see the point of storing BOTH forward and backward iterator if it appears that you will only use one :/
Maybe you should rethink your choice of container.
Usually you do not need to use reverse iterators to go backward,
currentfwd--
will go backwards, all though it might not work (which i assume you tried) with dequeue.
What you should really do is model your class here as a decorator of dequeue and implement your own Action iterators. That would be what I would do anyway.

How might I return a reversed adaptor wrapping a container?

I have a class which has-a deque which it uses as a stack (could be a vector, just happened to choose deque).
At any rate, I wish to allow consumers to iterate over the contents of the stack (something that std::stack cannot do). I am currently using push_back() to push items onto the stack, and hence if one iterates over the contents in forward ordering, one goes from bottom to the top of the stack.
I would prefer to expose things in reverse order, so that iterating over the stack using for (auto e: thestack) works in top-down fashion.
I found C++11 reverse range-based for-loop which shows a couple of solutions for reversing the iteration ordering for the new for-loop syntax (as well as range-based algorithms).
What is unclear to me is how to provide a simple mechanic for giving my users access to this automatically reversed deque.
e.g. without any real effort, I can simply allow const& access to the underlying deque:
const std::deque<T> & GetStack() const { return m_stack; }
and consumers could be responsible for the reversing:
for (auto e : reverse(m_toolstack.GetStack()))
Here, I am attempting to use the following solution for reverse:
template<class Fwd>
struct reverser_generic
{
Fwd &fwd;
reverser_generic(Fwd& fwd_): fwd(fwd_) {}
typedef std::reverse_iterator<typename Fwd::iterator> reverse_iterator;
reverse_iterator begin() { return reverse_iterator(std::end(fwd)); }
reverse_iterator end() { return reverse_iterator(std::begin(fwd)); }
};
template<class Fwd>
struct reverser_special
{
Fwd &fwd;
reverser_special(Fwd& fwd) : fwd(fwd) { }
auto begin() -> decltype(fwd.rbegin()) { return fwd.rbegin(); }
auto end() -> decltype(fwd.rend()) { return fwd.rend(); }
};
template<class Fwd>
auto reverse_impl(Fwd& fwd, long) -> decltype(reverser_generic<Fwd>(fwd))
{
return reverser_generic<Fwd>(fwd);
}
template<class Fwd>
auto reverse_impl(Fwd& fwd, int) -> decltype(fwd.rbegin(), reverser_special<Fwd>(fwd))
{
return reverser_special<Fwd>(fwd);
}
template<class Fwd>
auto reverse(Fwd&& fwd) -> decltype(reverse_impl(fwd,int(0)))
{
static_assert(!(std::is_rvalue_reference<Fwd&&>::value), "Cannot pass an rvalue reference to reverse()");
return reverse_impl(fwd,int(0));
}
The above all compiles and runs correctly using VS2012 (thanks to Jive Dadson et. al. for that solution).
However, in my stack facade, I really want to simply always return the reverse of the underlying container, but I am unclear on how to do so in a sensible fashion:
auto GetContents() const -> decltype(reverse(m_stack)) { return reverse(m_stack); }
The above errors, indicating that m_stack is unknown. this->m_stack is equally unknown.
How might I go about returning the "whatever it is that is the reverse of my member m_stack"?
Note, once that is answered, I also need "How do I return the const & of whatever is the decltype of reverse(m_stack)?
Is the declaration of GetContents before the declaration of m_stack?
Names in a late-specified return type must obey the same rules as names in the rest of the function signature, i.e. they cannot refer to class members that haven't been declared yet:
struct X
{
auto f() -> decltype(m_x) { return m_x; } // ERROR
int m_x;
auto g() -> decltype(m_x) { return m_x; } // OK
};
To make it work, either use std::declval to refer to the type (which means you must update the signature of GetContents if you change the type of m_stack from std::deque to std::vector) or ensure m_stack has been declared before you refer to it.