I'm trying to implement an iterator which encapsulates another iterator and performs range checking. Therefore I'm extending from that Iterator like so:
template<typename ITERATOR_T>
class r_iterator : public ITERATOR_T {
//...
r_iterator (ITERATOR_T begin, ITERATOR_T end) {
this->begin = begin;
this->end = end;
}
};
I want to use the iterators that are passed in the constructor to perform the range checking. My idea is to set the thing to which the "this"-iterator (i.e. r_iterator) points to to the element which is pointed to by the "begin" iterator from the constructor. This I would like to do so I can override certain methods like operator++ for example, perform range checking and then call the super method of the class I'm extending.
I would thus like to know whether it is possible to somehow set the element the "this"-iterator (r_iterator) points to assuming that I'm extending some STL Iterator class.
I could unfortunately not find any information about that in the c++ reference.
Regards and Thank you
There's no need to inherit, you can write a simple wrapper class like this:
#include <iostream>
#include <vector>
#include <stdexcept>
template <typename Iterator>
class MyIterator
{
Iterator _begin;
Iterator _end;
Iterator _cur;
public:
explicit MyIterator(Iterator begin, Iterator end)
: _begin(begin), _end(end)
{
_cur = _begin;
}
bool has_next() const
{
return (_cur != _end);
}
void operator++(int dummy)
{
if (!has_next())
throw std::out_of_range("Out of range.");
_cur++;
}
};
int main(int argc, char* argv[])
{
std::vector<int> v = {1, 2, 3};
MyIterator<std::vector<int>::iterator> my_it(v.begin(), v.end());
my_it++;
my_it++;
my_it++;
my_it++;
return 0;
}
Related
i've been trying to implement an iterator to my stack like this :
#include <iostream>
#include <stack>
#include <deque>
template <typename T, class container=std::deque<T>>
class MutantStack : public std::stack
{
public:
MutantStack(){}
~MutantStack(){}
MutantStack(const MutantStack &stack)
{
*this = stack;
}
typedef typename std::deque::iterator iterator;
};
but i couldn't make a begin and end iterator, how i can do it ?
and another question what the c.begin() in deque iterator means, i found this exemple :
iterator begin()
{
return this->c.begin();
}
I am not sure, if you selected the correct approach.
Because, you can use a std::deque in the first place. It offers all functionality that a stack offers. And more.
So maybe better use a std::deque or a std::vector.
Additionally, deriving from standard containers is not the best idea. You may read about that here on SO.
But if you want to do that for exceptional purposes, then simply take the address of the top(). This will be the last element in the underlying container. And if you subtract the size() of the stack (corrected by 1), then you have a pointer to the beginning of the underlying container.
And then you can use the artificial iterator and subscript operator [] as expected.
Please see the following example:
#include <vector>
#include <stack>
#include <iostream>
#include <algorithm>
#include <iterator>
using Number = int;
using UnderlyingContainer = std::vector<Number>;
using Stack = std::stack< Number, UnderlyingContainer>;
using StackIterator = Number *const;
int main()
{
// Put the test data onto the stack
Stack myStack{ UnderlyingContainer {1,2,3,4,5} };
if (not myStack.empty()) {
// Get "iterators"
StackIterator end = &myStack.top() + 1;
StackIterator begin = end - myStack.size();
Number *const & stk = begin;
for (size_t i{}; i < myStack.size(); ++i)
stk[i] = stk[i] + 10;
for (size_t i{}; i < myStack.size(); ++i)
std::cout << stk[i] << '\n';
std::transform(begin, end, begin, [](const Number n) {return n - 10; });
std::copy(begin, end, std::ostream_iterator<Number>(std::cout, "\n"));
}
}
So, it looks like we found what you want to have, but in reality, we simply work on the underlying container.
After some research I found this solution:
template <typename T, class container=std::deque<T>>
class MutantStack : public std::stack<T>
{
public:
MutantStack(){}
~MutantStack(){}
MutantStack(const MutantStack &stack)
{
*this = stack;
}
typedef typename container::iterator iterator;
iterator begin()
{
return this->c.begin();
}
iterator end()
{
return this->c.end();
}
};
The stack object inherits from the deque type like this :
template <class Type, class Container = deque<Type> > class stack;
but it exposes only a few methods such as: pop push empty swap and emplace. Therefore it has also the deque iterator. So I used it as above. The c in c.begin() and c.end() is a container_type defined in the stack class:
public:
typedef _Container container_type;
protected:
container_type c;
This means the c is the container and when typing c.begin() we get the first value in Mutantstack; it's like saying value[0] on an array.
Now my MutantStack class inherit from the std::stack class that's itself inherits from the std::deque class:
`MutantStack -> std::stack -> std::deque`
I implemented my own small UnboundArray class:
template <typename T>
class UnboundArray {
private:
std::vector<T> elementData;
public:
...
std::size_t size()
{
return elementData.size();
}
};
And I have a class in which I want to use my UnboundArray, especially I need to use a for loop on UnboundArray elements:
for (auto const &row : unbound_arrays) {
// loop over unbound array of unbound arrays and call its size method or something else
}
I'm really new to C++ iterators and do not know what path I should follow. Should I implement from scratch my iterator or should I make a member in my UnboundArray which is of type std::iterator?
If you mostly need to use a range based for loop with your custom class UnboundArray, you might start with implementing begin() and end() methods for UnboundArray:
auto begin() { return std::begin(elementData); }
auto end() { return std::end(elementData); }
so the loop works:
UnboundArray<int> unbound_array;
for (auto const &elem: unbound_array) { // ... }
wandbox example
It is important to note that you need const overloads in order to iterate through a const UnboundArray:
auto begin() const { return std::cbegin(elementData); }
auto end() const { return std::cend(elementData); }
I have a big vector of items that belong to a certain class.
struct item {
int class_id;
//some other data...
};
The same class_id can appear multiple times in the vector, and the vector is constructed once and then sorted by class_id. So all elements of the same class are next to each other in the vector.
I later have to process the items per class, ie. I update all items of the same class but I do not modify any item of a different class. Since I have to do this for all items and the code is trivially parallelizable I wanted to use Microsoft PPL with Concurrency::parallel_for_each(). Therefore I needed an iterator and came up with a forward iterator that returns the range of all items with a certain class_id as proxy object. The proxy is simply a std::pair and the proxy is the iterator's value type.
using item_iterator = std::vector<item>::iterator;
using class_range = std::pair<item_iterator, item_iterator>;
//iterator definition
class per_class_iterator : public std::iterator<std::forward_iterator_tag, class_range> { /* ... */ };
By now I was able to loop over all my classes and update the items like this.
std::vector<item> items;
//per_class_* returns a per_class_iterator
std::for_each(items.per_class_begin(), items.per_class_end(),
[](class_range r)
{
//do something for all items in r
std::for_each(r.first, r.second, /* some work */);
});
When replacing std::for_each with Concurrency::parallel_for_each the code crashed. After debugging I found the problem to be the following code in _Parallel_for_each_helper in ppl.h at line 2772 ff.
// Add a batch of work items to this functor's array
for (unsigned int _Index=0; (_Index < _Size) && (_First != _Last); _Index++)
{
_M_element[_M_len++] = &(*_First++);
}
It uses postincrement (so a temporary iterator is returned), dereferences that temporary iterator and takes the address of the dereferenced item. This only works if the item returned by dereferencing a temporary object survives, ie. basically if it points directly into the container. So fixing this is easy, albeit the per class std::for_each work loop has to be replaced with a for-loop.
//it := iterator somewhere into the vector of items (item_iterator)
for(const auto cur_class = it->class_id; cur_class == it->class_id; ++it)
{
/* some work */
}
My question is if returning proxy objects the way I did is violating the standard or if the assumption that every iterator dereferences into permanent data has been made by Microsoft for their library, but is not documented. At least I could not find any documentation on the iterator requirements for parallel_for_each() except that either a random access or a forward iterator are expected. I have seen the question about forward iterators and vector but since my iterator's reference type is const value_type& I still think my iterator is ok by the standard. So is a forward iterator returning a proxy object still a valid forward iterator? Or put another way, is it ok for an iterator to have a value type different from a type that is actually stored somewhere in a container?
Compilable example:
#include <vector>
#include <utility>
#include <cassert>
#include <iterator>
#include <memory>
#include <algorithm>
#include <iostream>
#include <ppl.h>
using identifier = int;
struct item
{
identifier class_id;
// other data members
// ...
bool operator<(const item &rhs) const
{
return class_id < rhs.class_id;
}
bool operator==(const item &rhs) const
{
return class_id == rhs.class_id;
}
//inverse operators omitted
};
using container = std::vector<item>;
using item_iterator = typename container::iterator;
using class_range = std::pair<item_iterator, item_iterator>;
class per_class_iterator : public std::iterator<std::forward_iterator_tag, class_range>
{
public:
per_class_iterator() = default;
per_class_iterator(const per_class_iterator&) = default;
per_class_iterator& operator=(const per_class_iterator&) = default;
explicit per_class_iterator(container &data) :
data_(std::addressof(data)),
class_(equal_range(data_->front())), //this would crash for an empty container. assume it's not.
next_(class_.second)
{
assert(!data_->empty()); //a little late here
assert(std::is_sorted(std::cbegin(*data_), std::cend(*data_)));
}
reference operator*()
{
//if data_ is unset the iterator is an end iterator. dereferencing end iterators is bad.
assert(data_ != nullptr);
return class_;
}
per_class_iterator& operator++()
{
assert(data_ != nullptr);
//if we are at the end of our data
if(next_ == data_->end())
{
//reset the data pointer, ie. make iterator an end iterator
data_ = nullptr;
}
else
{
//set to the class of the next element
class_ = equal_range(*next_);
//and update the next_ iterator
next_ = class_.second;
}
return *this;
}
per_class_iterator operator++(int)
{
per_class_iterator tmp{*this};
++(*this);
return tmp;
}
bool operator!=(const per_class_iterator &rhs) const noexcept
{
return (data_ != rhs.data_) ||
(data_ != nullptr && rhs.data_ != nullptr && next_ != rhs.next_);
}
bool operator==(const per_class_iterator &rhs) const noexcept
{
return !(*this != rhs);
}
private:
class_range equal_range(const item &i) const
{
return std::equal_range(data_->begin(), data_->end(), i);
}
container* data_ = nullptr;
class_range class_;
item_iterator next_;
};
per_class_iterator per_class_begin(container &c)
{
return per_class_iterator{c};
}
per_class_iterator per_class_end()
{
return per_class_iterator{};
}
int main()
{
std::vector<item> items;
items.push_back({1});
items.push_back({1});
items.push_back({3});
items.push_back({3});
items.push_back({3});
items.push_back({5});
//items are already sorted
//#define USE_PPL
#ifdef USE_PPL
Concurrency::parallel_for_each(per_class_begin(items), per_class_end(),
#else
std::for_each(per_class_begin(items), per_class_end(),
#endif
[](class_range r)
{
//this loop *cannot* be parallelized trivially
std::for_each(r.first, r.second,
[](item &i)
{
//update item (by evaluating all other items of the same class) ...
//building big temporary data structure for all items of same class ...
//i.processed = true;
std::cout << "item: " << i.class_id << '\n';
});
});
return 0;
}
When you're writing a proxy iterator, the reference type should be a class type, precisely because it can outlive the iterator it is derived from. So, for a proxy iterator, when instantiating the std::iterator base should specify the Reference template parameter as a class type, typically the same as the value type:
class per_class_iterator : public std::iterator<
std::forward_iterator_tag, class_range, std::ptrdiff_t, class_range*, class_range>
~~~~~~~~~~~
Unfortunately, PPL is not keen on proxy iterators and will break compilation:
ppl.h(2775): error C2338: lvalue required for forward iterator operator *
ppl.h(2772): note: while compiling class template member function 'Concurrency::_Parallel_for_each_helper<_Forward_iterator,_Function,1024>::_Parallel_for_each_helper(_Forward_iterator &,const _Forward_iterator &,const _Function &)'
with
[
_Forward_iterator=per_class_iterator,
_Function=main::<lambda_051d98a8248e9970abb917607d5bafc6>
]
This is actually a static_assert:
static_assert(std::is_lvalue_reference<decltype(*_First)>::value, "lvalue required for forward iterator operator *");
This is because the enclosing class _Parallel_for_each_helper stores an array of pointers and expects to be able to indirect them later:
typename std::iterator_traits<_Forward_iterator>::pointer _M_element[_Size];
Since PPL doesn't check that pointer is actually a pointer, we can exploit this by supplying a proxy pointer with an operator* and overloading class_range::operator&:
struct class_range_ptr;
struct class_range : std::pair<item_iterator, item_iterator> {
using std::pair<item_iterator, item_iterator>::pair;
class_range_ptr operator&();
};
struct class_range_ptr {
class_range range;
class_range& operator*() { return range; }
class_range const& operator*() const { return range; }
};
inline class_range_ptr class_range::operator&() { return{*this}; }
class per_class_iterator : public std::iterator<
std::forward_iterator_tag, class_range, std::ptrdiff_t, class_range_ptr, class_range&>
{
// ...
This works great:
item: item: 5
1
item: 3item: 1
item: 3
item: 3
Press any key to continue . . .
For your direct question, no, iterator does not have to be something which is related to any kind of container. About only requirements for an iterator are for it to be:
be copy-constructible, copy-assignable and destructible
support equality/inequality
be dereferencable
Iterator does not necessarily has to be tied to a particular container (see generators), and so it cannot be said that "it has to has same type as container" - because there is no container in generic case.
It seems, hovever, having a custom iterator class may be actually an overkill in your case. Here's why:
In C++, array/vector end iterator is and iterator pointing just behind the end of the last item.
Given a vector of objects of "classes" (in your definition) A,B,C, etc., filled like following:
AAAAAAABBBBBBBBBBBBCCCCCCCD.......
You can just take regular vector iterators that will act as your range starts and ends:
AAAAAAABBBBBBBBBBBBCCCCCCCD......Z
^ ^ ^ ^ ^
i1 i2 i3 i4 iN
For the 4 iterators you see here, following is true:
i1 is begin iterator for class A
i2 is end iterator for class A and begin iterator for class B
i3 is end iterator for class B and begin iterator for class C etc.
Hence, for each class you can have a pair of iterators which are start and end of the respective class range.
Hence, your processing is as trivial as:
for(auto it = i1; i!= i2; i++) processA(*it);
for(auto it = i2; i!= i3; i++) processB(*it);
for(auto it = i3; i!= i4; i++) processC(*it);
Each loop being trivially parallelizable.
parallel_for_each (i1; i2; processA);
parallel_for_each (i2; i3; processB);
parallel_for_each (i3; i4; processC);
To use a range-based for, you can introduce a substitute range class:
class vector_range<T> {
public:
vector<T>::const_iterator begin() {return _begin;};
vector<T>::const_iterator end() {return _end;};
// Trivial constructor filling _begin and _end fields
}
That is to say, you don't really need a proxy iterators to parallelize loops - the way C++ iterators are done is already ideally covers your case.
There are a number of use cases in the standard library, and I have run into my own code, situations where I want to pass an input and an output range that must be the same size, often to some algorithm. At present this requires three, or four if you want to be careful, iterators. Often there is then a bunch of checking to make sure the iterators make sense.
I am aware that array_view might, in some cases, coalesce pairs of being/end iterators but that still leaves checks required that the input and output array_views might be different size. Has there been any discussion on a class to contain both the input and the output range specifications? Maybe the range proposal solves some or all of this of this but I'm not clear how it does.
I often have a similar use case. I have found that the most versatile method is to pass a reference to an output 'container' concept rather than a range or pair of iterators. Then the algorithm is free to resize or extend the container as necessary and the possibility of buffer overruns disappears.
for (a simple contrived) example, something like:
template<class InputIter, class OutputContainer>
void encrypt_to(OutputContainer& dest, InputIter first, InputIter last)
{
dest.resize(last - first);
// ... todo: replace this with some actual encryption
std::copy(first, last, dest.begin());
}
For functions where I want to hide the implementation, I have an abstract interface representing the destination container. It needs virtual begin(), end() and resize() methods.
for example:
#include <iostream>
#include <algorithm>
#include <vector>
struct mutable_byte_buffer_concept {
using iterator=uint8_t*;
virtual iterator begin() = 0;
virtual iterator end() = 0;
virtual void resize(size_t newsize) = 0;
// note : no virtual destructor - by design.
};
template<class Container>
struct mutable_byte_buffer_model : mutable_byte_buffer_concept
{
mutable_byte_buffer_model(Container& container)
: container(container)
{
}
virtual iterator begin() override
{
return reinterpret_cast<iterator>(&container[0]);
}
virtual iterator end() override
{
return reinterpret_cast<iterator>(&container[0]) + container.size();
}
virtual void resize(size_t newsize) override
{
container.resize(newsize);
}
Container& container;
};
template<class Container>
auto make_mutable_buffer(Container& c)
-> mutable_byte_buffer_model<Container>
{
return { c };
}
// note: accepting an rvalue allows me to use polymorphism at the call site without needing any memory allocation
template<class Iter>
void copy_to(mutable_byte_buffer_concept&& dest, Iter first, Iter last)
{
dest.resize(last - first);
std::copy(first, last, dest.begin());
}
using namespace std;
auto main() -> int
{
auto a = "Hello, World"s;
string b;
vector<uint8_t> c;
string d;
copy_to(make_mutable_buffer(b), begin(a), end(a));
copy_to(make_mutable_buffer(c), begin(b), end(b));
copy_to(make_mutable_buffer(d), begin(c), end(c));
cout << d << endl;
return 0;
}
The proper way to iterate is to use iterators. However, I think by erasing, the iterator is invalidated.
Basically what I want to do is:
for(iterator it = begin; it != end; ++it)
{
if(it->somecondition() )
{
erase it
}
}
How could I do this without v[i] method?
Thanks
struct RemoveTimedEvent
{
bool operator()(const AguiTimedEvent& pX, AguiWidgetBase* widget) const
{
return pX.getCaller() == widget;
}
};
void AguiWidgetContainer::clearTimedEvents( AguiWidgetBase* widget )
{
std::vector<AguiTimedEvent>::iterator it = std::remove_if(timedEvents.begin(),
timedEvents.end(), RemoveTimedEvent());
timedEvents.erase(it, timedEvents.end());
}
erase() returns a new iterator:
for(iterator it = begin; it != end(container) /* !!! */;)
{
if (it->somecondition())
{
it = vec.erase(it); // Returns the new iterator to continue from.
}
else
{
++it;
}
}
Note that we can no longer compare it against a precalculated end, because we may erase it and therefore invalidate it. We must get the end explicitly each time.
A better method might be to combine std::remove_if and erase(). You change from being O(N2) (every element gets erased and shifted as you go) to O(N):
iterator it = std::remove_if(begin, end, pred);
vec.erase(it, vec.end());
Where pred is your removal predicate, such as:
struct predicate // do choose a better name
{
bool operator()(const T& pX) const // replace T with your type
{
return pX.shouldIBeRemoved();
}
};
iterator it = std::remove_if(begin, end, predicate());
vec.erase(it, vec.end());
In your case, you can make it pretty general:
class remove_by_caller
{
public:
remove_by_caller(AguiWidgetBase* pWidget) :
mWidget(pWidget)
{}
// if every thing that has getCaller has a base, use that instead
template <typename T> // for now a template
bool operator()(const T& pX) const
{
return pX.getCaller() == mWidget;
}
private:
AguiWidgetBase* mWidget;
};
std::vector<AguiTimedEvent>::iterator it =
std::remove_if(timedEvents.begin(), timedEvents.end(), remove_by_caller(widget));
timedEvents.erase(it, timedEvents.end());
Note lambda's exist to simplify this process, both in Boost and C++11.