I have a collection of object of type "T" that i want to iterate through. An object of type "T" has two important properties:
int r; // row number
int c; // column number
I would like to define an iterator that allows me to iterate through all elements of the collection.
This can be done using:
std::vector<T> v;
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
....
}
However, I would like the iterator to have one more property. I would like to be able to call
it.nextrow()
calling this function should return the element "e" of v where e.r + 1 = ec.r and e.c = ec.c, where ec is the current element pointed by the iterator. I.e. calling it.nextrow() should give me a pointer to the element where column is the same, but row is incremented by one. Hope it makes sense.
I am not sure what I need to do in order for this to work, as I am fairly new to advanced c++ concepts. Can anybody help me?
Not everything has to be a member function. Would you accept a iterator nextRow(iterator current, iterator begin, iterator end) free function?
template<typename Iterator>
Iterator nextRow(Iterator needle, Iterator begin, Iterator end)
{
return std::find_if(begin, end, [needle](const T & elem) { return (elem.r == needle->r + 1) && (elem.c == needle->c); });
}
If your vector is always sorted, you don't need a separate begin, just use needle.
If you do need this to be a part of a wrapper iterator, that type will need to contain a begin and end.
template <typename Iterator>
class SearchableIterator
{
Iterator wrapped, begin, end;
public:
difference_type Iterator::difference_type;
value_type Iterator::value_type;
pointer Iterator::pointer;
reference Iterator::reference
iterator_category Iterator::iterator_category
SearchableIterator(Iterator wrapped, Iterator begin, Iterator end)
: wrapped(wrapped), begin(begin), end(end) {}
// All the members, calling that member of wrapped (see std::reverse_iterator for guidance)
SearchableIterator nextRow()
{
return SearchableIterator(std::find_if(begin, end, [this](const T & elem) { return (elem.r == wrapped->r + 1) && (elem.c == wrapped->c); }), begin, end);
}
}
Iterators are copyable.
You can
derive from the container's iterator for your container,
add construction from the container's iterator,
add your extra property members,
and declare that begin(), end(), etc from your custom container return your derived iterator.
Assuming your data are packed in a vector with consecutive items for all columns of a row followed by items of the next row, you would just need *(iterator + column_count) to access the next-row-same-column value (don't try this on an iterator that's already pointing into the last row of data)
You can create a wrapper iterator similar to Implement custom iterator for c++ std container and give it a specific column count as additional information:
template<typename T, int colsize, typename TIterator = std::vector<T>::iterator>
class MyRowIterator : public std::iterator<std::forward_iterator_tag, T>
{
private:
TIterator m_pter;
public:
MyRowIterator(TIterator& value): m_pter(value)
{
}
MyRowIterator(const MyRowIterator& other_it): m_pter(other_it.m_pter)
{
}
MyRowIterator& operator++()
{
++m_pter;
return *this;
}
bool operator!=(const MyRowIterator& rhs)
{
return m_pter != rhs.m_pter;
}
T& operator*()
{
return (*m_pter);
}
// here it is
T& nextrow()
{
return *(m_pter+colsize);
}
};
Usage example:
void Test()
{
std::vector<int> data;
// 2 rows each 10 columns
data.resize(20);
for (auto& item : data)
{
item = 0;
}
data[2] = 1;
data[12] = 5;
// don't iterate the last line, else nextrow() will access out of bounds!
for (MyRowIterator<int, 10> iter = data.begin(); iter != (data.end()-10); iter++)
{
std::cout << *iter << " # " << iter.nextrow() << std::endl;
}
}
Related
I have a vector of vectors of strings. I want to find the lengths of the longest string in each column. All the subvectors are of the same length and have an element stored in it, so it would be rather easy to find it with two for loops and reversed indices.
vector<vector<string>> myvec = {
{ "a", "aaa", "aa"},
{"bb", "b", "bbbb"},
{"cc", "cc", "ccc"}
};
But is it possible to do it with iterators without using indices?
Assuming the inner vectors are all the same length, you can have something like
template <typename T>
class columnwise {
std::vector<std::vector<T>> * underlying;
struct proxy {
std::vector<std::vector<T>> * underlying;
std::vector<T>::difference_type offset;
struct iterator {
std::vector<std::vector<T>>::iterator outer;
std::vector<T>::difference_type offset;
using reference = typename std::vector<T>::reference;
using pointer = typename std::vector<T>::pointer;
iterator operator++() { ++outer; return *this; }
reference operator*() { return *(outer->begin() + offset); }
pointer operator->() { return (outer->begin() + offset).operator->(); }
bool operator==(iterator rhs) { return (outer == rhs.outer) && (offset == rhs.offset); }
};
public:
iterator begin() { return { underlying->begin(), offset }; }
iterator end() { return { underlying->end(), offset }; }
};
struct iterator {
// member type aliases
std::vector<std::vector<T>> * underlying;
std::vector<T>::difference_type offset;
iterator operator++() { ++offset; return *this; }
proxy operator*() { return { underlying, offset }; }
bool operator==(iterator rhs) { return (underlying== rhs.underlying) && (offset == rhs.offset); }
};
std::vector<T>::difference_type inner_size() { if (auto it = underlying->begin(); it != underlying->end()) { return it->size(); } return 0; }
public:
columnwise(std::vector<std::vector<T>> & vec) : underlying(&vec) {}
iterator begin() { return { underlying, 0 }; }
iterator end() { return { underlying, inner_size() }; }
};
Which iterates as you expect.
What about something like this?
std::vector<std::size_t> max_lengths(myvec.front().size(), 0);
for (auto const& strings : myvec) {
std::transform(max_lengths.begin(), max_lengths.end(), strings.begin(), max_lengths.begin(),
[](std::size_t l, std::string const& s) {
return std::max(l, s.size());
}
);
}
Demo
Here is a solution using C++20 ranges and lambdas that is similar to Nelfeals answer:
// returns a function returning the i-th element of an iterable container
auto ith_element = [](size_t i) {
return [i](auto const& v){
return v[i];
};
};
// returns a range over the i-th column
auto column = [ith_element](size_t i) {
return std::views::transform(ith_element(i)); // returns a range containing only the i-th elements of the elements in the input range
};
// returns the size of something
auto length = [](auto const& s){ return s.size(); };
// returns the max length of the i-th column
auto max_length_of_col = [column, length](auto const& v, size_t i) {
return std::ranges::max(
v | column(i) | std::views::transform(length)
);
};
I personally like how the ranges library helps you convey intent with your code, rather than having to prescribe the procedure to achieve your goal.
Note that if you replace the body of inner lambda in ith_element with the following block, it will also work for iterable containers without random access.
auto it = v.cbegin();
std::ranges::advance(it, i);
return *it
Demo
As a final remark, this solution lets you iterate over one column given an index of the column. I would advise against implementing a column iterator for vector<vector>: The existence of an iterator implies that something exists in memory that you can iterate over. The existence of columns is only implied by the additional information that you have given us, namely that all rows have the same length. If you do want iterators both for columns and rows, I would wrap your container in a new type (usually called matrix or similar) that properly conveys that intent. Then you can implement iterators for that new type, see Calath's answer.
EDIT:
I realized that my argument against a column iterator can be used as an argument against the column function in this answer as well. So here is a solution that let's you iterate over columns in a range-based for loop intead of iterating over column indices:
for (auto column : columns(myvec)){
std::cout << max_length(column) << std::endl;
}
This is a code example using std::reverse_iterator:
template<typename T, size_t SIZE>
class Stack {
T arr[SIZE];
size_t pos = 0;
public:
T pop() {
return arr[--pos];
}
Stack& push(const T& t) {
arr[pos++] = t;
return *this;
}
auto begin() {
return std::reverse_iterator(arr+pos);
}
auto end() {
return std::reverse_iterator(arr);
// ^ does reverse_iterator take this `one back`? how?
}
};
int main() {
Stack<int, 4> s;
s.push(5).push(15).push(25).push(35);
for(int val: s) {
std::cout << val << ' ';
}
}
// output is as expected: 35 25 15 5
When using std::reverse_iterator as an adaptor for another iterator, the newly adapted end shall be one before the original begin. However calling std::prev on begin is UB.
How does std::reverse_iterator hold one before begin?
Initialization of std::reverse_iterator from an iterator does not decrease the iterator upon initialization, as it would then be UB when sending begin to it (one cannot assume that std::prev(begin) is a valid call).
The trick is simple, std::reverse_iterator holds the original iterator passed to it, without modifying it. Only when it is being dereferenced it peeks back to the actual value. So in a way the iterator is pointing inside to the next element, from which it can get the current.
It would look something like:
// partial possible implementation of reverse_iterator for demo purpose
template<typename Itr>
class reverse_iterator {
Itr itr;
public:
constexpr explicit reverse_iterator(Itr itr): itr(itr) {}
constexpr auto& operator*() {
return *std::prev(itr); // <== only here we peek back
}
constexpr auto& operator++() {
--itr;
return *this;
}
friend bool operator!=(reverse_iterator<Itr> a, reverse_iterator<Itr> b) {
return a.itr != b.itr;
}
};
This is however an internal implementation detail (and can be in fact implemented in other similar manners). The user of std::reverse_iterator shall not be concerned with how it is implemented.
I have a class that contains the vector of elements of the specific class. The main idea is to generate periodic sequence of the elements, based on the one period of the sequence (elems_) and the number of the periods (nperiod_) so I do not need to store all elements, but just one period.
class PeriodicContainer
{
private:
std::vector<Class> elems_; // elements
size_t nperiod_; // period of repetition of elems_
public:
PeriodicContainer();
PeriodicContainer(const std::vector<Class>& elems, size_t nperiod);
/*...*/
}
Is it possible to implement custom iterator for the PeriodicContainer so that I can do things like (semi-pseudo-code):
PeriodicContainer container({Class(1), Class(2)}, 4);
for (auto it : container)
std::cout << it << '\n';
and the output will be
Class(1)
Class(2)
Class(1)
Class(2)
Class(1)
Class(2)
Class(1)
Class(2)
If you can use range-v3, you can do:
namespace rv = ranges::views;
std::vector<Class> Container { Class(1), Class(2) };
for (auto it : rv::repeat_n(Container, 4) | rv::join)
std::cout << it;
and not have to write any additional code yourself. This will also work for any contiguous container, not just std::vector.
Here's a demo.
If your underlying container is simply a std::vector, then you know that it's a contiguous container -- which actually makes this quite easy.
You can form an iterator from the following:
A pointer (or reference) to the container being iterated, and
The current iteration count (note: not 'index'). This will be used as "index" into the underlying container's operator[] after wrapping around the container's size().
The behavior of this iterator would be simply:
Each increment just increments the current count
Each dereference returns (*elems_)[current_ % elems_->size()], which will account for the loop-around for the "period".
The begin() would simply return an iterator with a 0 count, and
The end() would return an iterator with a count of elems_.size() * nperiod_
An example of what this could look like as a LegacyForwardIterator is the following:
template <typename T>
class PeriodicContainerIterator
{
public:
using value_type = T;
using reference = T&;
using pointer = T*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
PeriodicContainerIterator(std::vector<T>* elems, std::size_t current)
: elems_{elems},
current_{current}
{}
reference operator*() {
return (*elems_)[current_ % elems_->size()]
}
pointer operator->() {
return &(*elems_)[current_ % elems_->size()];
}
PeriodicContainerIterator& operator++() const {
++current_;
return (*this);
}
PeriodicContainerIterator operator++(int) const {
auto copy = (*this);
++current_;
return copy;
}
bool operator==(const PeriodicContainerIterator& other) const {
return current_ == other.current_;
}
bool operator!=(const PeriodicContainerIterator& other) const {
return current_ != other.current_;
}
private:
std::vector<T>* elems_;
std::size_t current_;
};
The container would then define begin() and end() as:
PeriodicContainerIterator<Class> begin() {
return PeriodicContainerIterator<Class>{&elems_, 0};
}
PeriodicContainerIterator<Class> end() {
return PeriodicContainerIterator<Class>{&elems_, elems_->size() * nperiod_};
}
You could easily make this all the way up to a LegacyRandomAccessIterator, but this requires a lot of extra functions which will bulk this answer.
If you don't specifically need this as an iterator but just want a simple way to visit each element in the periodic sequence, it might be easier to read / understand if you were to make this into a for_each-like call that expects a callback instead. For example:
template <typename Fn>
void forEach(Fn&& fn)
{
for (auto i = 0; i < nperiod_; ++i) {
for (auto& e : elems_) {
fn(e);
}
}
}
Which allows for use like:
container.forEach([&](auto& e){
// 'e' is each visited element
});
I have a vector< Object > myvec which I use in my code to hold a list of objects in memory. I keep a pointer to the current object in that vector in the "normal" C fashion by using
Object* pObj = &myvec[index];
This all works fine if... myvec doesn't grow big enough that it is moved around during a push_back at which time pObj becomes invalid - vectors guarantee data is sequential, hence they make no effort to keep the vector at the same memory location.
I can reserve enough space for myvec to prevent this, but I dnt' like that solution.
I could keep the index of the selected myvec position and when I need to use it just access it directly, but it's a costly modification to my code.
I'm wondering if iterators keep the their references intact as a vector is reallocated/moved and if so can I just replace
Object* pObj = &myvec[index];
by something like
vector<Object>::iterator = myvec.begin()+index;
What are the implication of this?
Is this doable?
What is the standard pattern to save pointers to vector positions?
Cheers
No... using an iterator you would have the same exact problem. If a vector reallocation is performed then all iterators are invalidated and using them is Undefined Behavior.
The only solution that is reallocation-resistant with an std::vector is using the integer index.
Using for example std::list things are different, but also the are different efficiency compromises, so it really depends on what you need to do.
Another option would be to create your own "smart index" class, that stores a reference to the vector and the index. This way you could keep just passing around one "pointer" (and you could implement pointer semantic for it) but the code wouldn't suffer from reallocation risks.
Iterators are (potentially) invalidated by anything that could resize the vector (e.g., push_back).
You could, however, create your own iterator class that stored the vector and an index, which would be stable across operations that resized the vector:
#include <iterator>
#include <algorithm>
#include <iostream>
#include <vector>
namespace stable {
template <class T, class Dist=ptrdiff_t, class Ptr = T*, class Ref = T&>
class iterator : public std::iterator<std::random_access_iterator_tag, T, Dist, Ptr, Ref>
{
T &container_;
size_t index_;
public:
iterator(T &container, size_t index) : container_(container), index_(index) {}
iterator operator++() { ++index_; return *this; }
iterator operator++(int) { iterator temp(*this); ++index_; return temp; }
iterator operator--() { --index_; return *this; }
iterator operator--(int) { stable_itertor temp(*this); --index_; return temp; }
iterator operator+(Dist offset) { return iterator(container_, index_ + offset); }
iterator operator-(Dist offset) { return iterator(container_, index_ - offset); }
bool operator!=(iterator const &other) const { return index_ != other.index_; }
bool operator==(iterator const &other) const { return index_ == other.index_; }
bool operator<(iterator const &other) const { return index_ < other.index_; }
bool operator>(iterator const &other) const { return index_ > other.index_; }
typename T::value_type &operator *() { return container_[index_]; }
typename T::value_type &operator[](size_t index) { return container_[index_ + index]; }
};
template <class T>
iterator<T> begin(T &container) { return iterator<T>(container, 0); }
template <class T>
iterator<T> end(T &container) { return iterator<T>(container, container.size()); }
}
#ifdef TEST
int main() {
std::vector<int> data;
// add some data to the container:
for (int i=0; i<10; i++)
data.push_back(i);
// get iterators to the beginning/end:
stable::iterator<std::vector<int> > b = stable::begin(data);
stable::iterator<std::vector<int> > e = stable::end(data);
// add enough more data that the container will (probably) be resized:
for (int i=10; i<10000; i++)
data.push_back(i);
// Use the previously-obtained iterators:
std::copy(b, e, std::ostream_iterator<int>(std::cout, "\n"));
// These iterators also support most pointer-like operations:
std::cout << *(b+125) << "\n";
std::cout << b[150] << "\n";
return 0;
}
#endif
Since we can't embed this as a nested class inside of the container like a normal iterator class, this requires a slightly different syntax to declare/define an object of this type; instead of the usual std::vector<int>::iterator whatever;, we have to use stable::iterator<std::vector<int> > whatever;. Likewise, to obtain the beginning of a container, we use stable::begin(container).
There is one point that may be a bit surprising (at least at first): when you obtain a stable::end(container), that gets you the end of the container at that time. As shown in the test code above, if you later add more items to the container, the iterator your obtained previously is not adjusted to reflect the new end of the container -- it retains the position it had when you obtained it (i.e., the position that was the end of the container at that time, but isn't any more).
No, iterators are invalidated after vector growth.
The way to get around this problem is to keep the index to the item, not a pointer or iterator to it. This is because the item stays at its index, even if the vector grows, assuming of course that you don't insert any items before it (thus changing its index).
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.