I have a need for a "container" that acts like the following. It has 2 subcontainers, called A and B, and I need to be able to iterate over just A, just B, and A and B combined. I don't want to use extra space for redundant data, so I thought of making my own iterator to iterate over A and B combined. What is the easiest way to make your own iterator? Or, what is another way to do this?
EDIT Ultimately, I don't think it was good design. I have redesigned the entire class heirarchy. +1 for refactoring. However, I did solve this problem sufficiently. Here's an abbreviated version of what I did, for reference; it uses boost::filter_iterator. Let T be the type in the container.
enum Flag
{
A_flag,
B_flag
};
class T_proxy
{
public:
T_proxy(const T& t, Flag f) : t_(t), flag_(f) {}
operator T() const {return t_;}
Flag flag() const {return flag_;}
class Compare
{
public:
Compare(Flag f) : matchFlag_(f) {}
operator() (const T_proxy& tp) {return tp.flag() == matchFlag_;}
private:
Flag matchFlag_;
};
private:
T t_;
Flag flag_;
};
class AB_list
{
public:
typedef T_proxy::Compare Compare;
typedef vector<T_proxy>::iterator iterator;
typedef boost::filter_iterator<Compare, iterator> sub_iterator;
void insert(const T& val, Flag f) {data_.insert(T_proxy(val, f));}
// other methods...
// whole sequence
iterator begin() {return data_.begin();}
iterator end() {return data_.end();}
// just A
sub_iterator begin_A() {return sub_iterator(Compare(A_flag), begin(), end());
sub_iterator end_A() {return sub_iterator(Compare(A_flag), end(), end());
// just B is basically the same
private:
vector<T_proxy> data_;
};
// usage
AB_list mylist;
mylist.insert(T(), A_flag);
for (AB_list::sub_iterator it = mylist.begin_A(); it != mylist.end_A(); ++it)
{
T temp = *it; // T_proxy is convertible to T
cout << temp;
}
I will repost my answer to a similar question. I think this will do what you want.
Use a library like Boost.MultiIndex to do what you want. It scales well and there is a lot less boiler plate code if you want to add new indexes. It is also usually more space and time efficient
typedef multi_index_container<
Container,
indexed_by<
sequenced<>, //gives you a list like interface
ordered_unique<Container, std::string, &Container::a_value>, //gives you a lookup by name like map
ordered_unique<Container, std::string, &Container::b_value> //gives you a lookup by name like map
>
> container;
If you are iterating over one index, you can switch to another index by using the iterator projection concept in the library.
Have one container which stores the value you are interested in together with a flag indicating whether it is in A or B.
You could also create a single container containing std::pair<> objects.
Billy3
Related
I tried to simplify the situation as good as possible.
Basically I have a class that represents a dynamic Array (here shown as class Array with size 4) and secondly a class which is a HashMap, and has an Array of Arrays as a member (here represented by class Bar).
Both classes implement begin() and end() so you can use a foreach loop to iterate over all elements.
The iterator type of Array is simply T* and const T* for the const variant.
For Bar there is a special class Iterator, which correctly iterates through all members of the Array<Array<T>>.
You should now have a look at the classes I provided, so you know what exactly I'm talking about.
But now there is a problem when I call bar.begin() on a const Bar object
The Iterator class determines the ArrayIterator and ElementIterator types automatically (via decltype of T::begin()), because in my real application almost everything is templated and that's why I don't know the exact type in advance.
I figured out the problem is that decltype(((T*)nullptr)->begin()) always chooses the non-const begin() function of T, which absolutely makes sense since I haven't written (const T*)nullptr.
If I now call it from a const context, it will fail to assign a const T* like data.last().end() to the internal T* from the decltype which actually should be a const T*.
I can workaround the problem by declaring a second class ConstIterator which does everything exactly like the non-const one, but uses (const Array<T>*)nullptr and (const T*)nullptr inside the decltype statements.
So what can I do without copying the whole Bar::Iterator class?
Simplified code:
template<class T>
class Array
{
T data[4];
T last() { return data[3]; }
T* begin() { return data; };
T* end() { return data + 4; };
const T* begin() const { return data; };
const T* end() const { return data + 4; };
}
template<class T>
class Bar
{
class Iterator
{
using ArrayIterator = decltype(((Array<T>*)nullptr)->begin());
using ElementIterator = decltype(((T*)nullptr)->begin());
Iterator(const ArrayIterator& beg, const ArrayIterator& end)
{
//initialize the iterator to the first element of the first array
//(and rembember end)
};
Iterator(const ElementIterator& cur)
{
//initialize the iterator to the current element
};
//++ will iterate go to next element and eventually jump to the next array.
//== returns true if the current element is the same
};
Array<T> data;
Iterator begin() { return Iterator(data.begin(), data.end()); };
Iterator end() { return Iterator(data.last().end()); };
Iterator begin() const { return Iterator(data.begin(), data.end()); };
Iterator end() const { return Iterator(data.last().end()); };
};
Actually, you will have to implement ConstIterator class. See, for example, the standard containers like vector or list, you have both iterator and const_iterator there, and they're different classes. Const correctness is hard sometimes. However, you can get away with code duplication by using templates or const_cast (see, for example, Scott Myers Effective C++)
I have a C++ class that acts like a container: it has size() and operator[] member functions. The values stored "in" the container are std::tuple objects. However, the container doesn't actually hold the tuples in memory; instead, it constructs them on-demand based on underlying data stored in a different form.
std::tuple<int, int, int>
MyContainer::operator[](std::size_t n) const {
// Example: draw corresponding elements from parallel arrays
return { underlying_data_a[n], underlying_data_b[n], underlying_data_c[n] };
}
Hence, the return type of operator[] is a temporary object, not a reference. (This means it's not an lvalue, so the container is read-only; that's OK.)
Now I'm writing an iterator class that can be used to traverse the tuples in this container. I'd like to model RandomAccessIterator, which depends on InputIterator, but InputIterator requires support for the expression i->m (where i is an iterator instance), and as far as I can tell, an operator-> function is required to return a pointer.
Naturally, I can't return a pointer to a temporary tuple that's constructed on-demand. One possibility that comes to mind is to put a tuple instance into the iterator as a member variable, and use it to store a copy of whichever value the iterator is currently positioned on:
class Iterator {
private:
MyContainer *container;
std::size_t current_index;
// Copy of (*container)[current_index]
std::tuple<int, int, int> current_value;
// ...
};
However, updating the stored value will require the iterator to check whether its current index is less than the container's size, so that a past-the-end iterator doesn't cause undefined behavior by accessing past the end of the underlying arrays. That adds (a small amount of) runtime overhead — not enough to make the solution impractical, of course, but it feels a little inelegant. The iterator shouldn't really need to store anything but a pointer to the container it's iterating and the current position within it.
Is there a clean, well-established way to support operator-> for iterator types that construct their values on-demand? How would other developers do this sort of thing?
(Note that I don't really need to support operator-> at all — I'm implementing the iterator mainly so that the container can be traversed with a C++11 "range for" loop, and std::tuple doesn't have any members that one would typically want to access via -> anyway. But I'd like to model the iterator concepts properly nonetheless; it feels like I'm cutting corners otherwise. Or should I just not bother?)
template<class T>
struct pseudo_ptr {
T t;
T operator*()&&{return t;}
T* operator->(){ return &t; }
};
then
struct bar { int x,y; };
struct bar_iterator:std::iterator< blah, blah >{
// ...
pseudo_ptr<bar> operator->() const { return {**this}; }
// ...
};
This relies on how -> works.
ptr->b for pointer ptr is simply (*ptr).b.
Otherwise it is defined as (ptr.operator->())->b. This evaluates recursively if operator-> does not return a pointer.
The pseudo_ptr<T> above gives you a wrapper around a copy of T.
Note, however, that lifetime extension doesn't really work. The result is fragile.
Here's an example relying on the fact that operator-> is applied repeatedly until a pointer is returned. We make Iterator::operator-> return the Contained object as a temporary. This causes the compiler to reapply operator->. We then make Contained::operator-> simply return a pointer to itself. Note that if we don't want to put operator-> in the Contained on-the-fly object, we can wrap it in a helper object that returns a pointer to the internal Contained object.
#include <cstddef>
#include <iostream>
class Contained {
public:
Contained(int a_, int b_) : a(a_), b(b_) {}
const Contained *operator->() {
return this;
}
const int a, b;
};
class MyContainer {
public:
class Iterator {
friend class MyContainer;
public:
friend bool operator!=(const Iterator &it1, const Iterator &it2) {
return it1.current_index != it2.current_index;
}
private:
Iterator(const MyContainer *c, std::size_t ind) : container(c), current_index(ind) {}
public:
Iterator &operator++() {
++current_index;
return *this;
}
// -> is reapplied, since this returns a non-pointer.
Contained operator->() {
return Contained(container->underlying_data_a[current_index], container->underlying_data_b[current_index]);
}
Contained operator*() {
return Contained(container->underlying_data_a[current_index], container->underlying_data_b[current_index]);
}
private:
const MyContainer *const container;
std::size_t current_index;
};
public:
MyContainer() {
for (int i = 0; i < 10; i++) {
underlying_data_a[i] = underlying_data_b[i] = i;
}
}
Iterator begin() const {
return Iterator(this, 0);
}
Iterator end() const {
return Iterator(this, 10);
}
private:
int underlying_data_a[10];
int underlying_data_b[10];
};
int
main() {
MyContainer c;
for (const auto &e : c) {
std::cout << e.a << ", " << e.b << std::endl;
}
}
I have a class:
class X {
vector<shared_ptr<T>> v_;
public:
vector<shared_ptr<const T>> getTs() { return v_; }
};
It has a vector of shared_ptr of type T. For some reason, it needs to expose a method to return this vector. However, I don't want the content of the vector to be modified, neither are the objects being pointed to. So I need to return a vector of shared_ptr<const T>.
My question is, is there any efficient way to achieve this? If I simply return it, it works, but it needs to reconstruct a vector, which is kind of expensive.
Thanks.
You can not do that directly - but you can define "views" on your container that let you do something very similar, if you want to make sure that your pointees are const:
boost::any_range<
std::shared_ptr<const int>,
boost::random_access_traversal_tag,
std::shared_ptr<const int>,
std::ptrdiff_t
> foo(std::vector<std::shared_ptr<int>>& v)
{
return v;
}
A simple transform iterator adapter / transformed range might do the trick as well, I just used this to illustrate the point.
Why not return it as a set of iterators?
class X {
vector<shared_ptr<T>> v_;
class const_iterator : std::iterator< std::bidirectional_iterator_tag, T >
{
vector<shared_ptr<T>>::iterator it;
const_iterator( vector<shared_ptr<T>>::iterator& v ) :it (v) { }
const T& operator*() { return const_cast<const T>( **it ); }
//forward all methods
}
public:
const_iterator ts_begin() { return const_iterator(v_.begin()); }
const_iterator ts_end() { return const_iterator(v_.end()); }
};
or something similar? That gives you full control over the type and how it's accessed. Plus you can later change the type w/o changing the api.
You are returning by value, so the cost is the same whether you return a copy of the original, vector or a copy of a vector of shared_ptr<T const>: One memory allocation and N atomic increments (approx.).
If what you want to avoid is the creation of the returned vector (i.e. return by value), then it is impossible as different template instantiations are unrelated types no matter how related the arguments to the template are.
Question Synopsis
Given a std::vector<T>, how can I create a view that exposes the interface of a std::vector<std::pair<T, T>>, where each pair consists of two consecutive elements in the underlying vector?
Details
The goal is to create multiple container abstractions over the same storage, which is a std::vector<T>. The type T is some sort of discriminated union, à la Boost Variant. The storage requirement is given, otherwise I would simply use a std::vector<std::pair<T, T>>. The views over the storage I would like to support are sets (unique elements) and tables (associative array, unique keys). While the former is straight-forward by ensuring the set uniqueness property, the latter requires handling keys and values.
To support associative array semantics over a std::vector<T>, I am currently thinking that the best way would be to create a view of the form std::vector<std::pair<T, T>>, and that this view would allow me use STL algorithms to maintain the required properties. Does this sound like a good strategy? Are there any other ideas?
Related
If I had an iterator i that goes over every even element and iterator j that goes through every odd element, Boost's zip iterator comes to mind, which would enable iteration in (i,j) pairs. But my use case is slightly different in that I do not have two separate containers.
It seems that Boost's iterator_facade is indeed what I want. Here is a toy example (with rough edges):
#include <algorithm>
#include <iostream>
#include <vector>
#include <boost/iterator/iterator_facade.hpp>
template <typename Value>
class pair_iterator
: public boost::iterator_facade<
pair_iterator<Value>
, Value
, boost::random_access_traversal_tag
, std::pair<Value&, Value&>
, typename std::vector<Value>::difference_type
>
{
public:
typedef std::vector<Value> vector_type;
typedef typename vector_type::difference_type difference_type;
typedef typename vector_type::iterator iterator;
pair_iterator()
: i_(0)
{
}
explicit pair_iterator(iterator i)
: i_(i)
{
}
private:
friend class boost::iterator_core_access;
bool equal(pair_iterator<Value> const& other) const
{
return i_ == other.i_;
}
void increment()
{
++i_;
++i_;
}
std::pair<Value&, Value&> dereference() const
{
return { std::ref(*i_), std::ref(*(i_ + 1)) };
}
void advance(difference_type n)
{
i_ += n << 1;
}
difference_type distance_to(pair_iterator<Value> const& other) const
{
return other.i_ - i_;
}
iterator i_;
};
int main()
{
typedef pair_iterator<int> int_map_iterator;
std::vector<int> v{2, 20, 3, 30, 5, 50, 7, 70};
int_map_iterator first(v.begin());
int_map_iterator last(v.end());
std::for_each(first + 1, last,
[](std::pair<int&, int&> p)
{
std::cout
<< p.first << " -> "
<< p.second << std::endl;
});
return 0;
}
The output is:
3 -> 30
5 -> 50
7 -> 70
Issues
Conversion from iterator to const_iterator has not yet been addressed by this example.
The iterator only works when the underlying vector has even size and needs a more conservative implementation of dereference().
The first thing to note is that you won't be able to expose a std::pair<T const, T>& as a means to modify the objects. What may be sufficantly close, however, is a std::pair<T const, T&> as you'll only be able to change the second part.
With this out of the way it seems you need
An iterator type which skips every other value and is used to iterate over the keys (elements with even indices) and the values (elements with odd indices).
Something like a "zip iterator" which takes two iterators and exposes a std::pair<T const, T&> obtained from them.
I'm writing some C++ code that manipulates a bunch of vectors that are changing in size and are thus being reallocated constantly.
I would like to get a "pointer" into these vectors that remains valid even after reallocation of the vector. More specifically, I just want these "pointers" to remember which vector they point into and the index to which they point. When I dereference them using the standard (*ptr) syntax, I just want them to do the obvious lookup.
Obviously, actual pointers will not be valid after reallocation, and my understanding is that iterators aren't valid after reallocation either. Note also that I don't care if elements are inserted before my objects, so these "pointers" really don't have to remember anything but a vector and an index.
Now, I could easily write such a class myself. Has anyone (Boost? STL?) done it for me already?
Edit: The answers don't address my question. I asked if this functionality is any standard library. I take the responses as a "no"?
Try a std::pair< vector*, int>, as neither the position of the vector nor the index of the element changes.
Or, as a class:
template<class T> class VectorElementPointer
{
vector<T>& vectorref;
typename vector<T>::size_type index;
public:
VectorElementPointer(vector<T>& vref, typename vector<T>::size_type index):vectorref(vref),index(index){}
T& operator*() const {return vectorref[index];}
T* operator->() const {return &vectorref[index];}
};
This is the easiest solution that comes to my mind, as neither the STL nor Boost contains anything to do it easier.
An article on persistent iterators, complete with implementation.
To summarize some ideas. Here is the minimalist wrapper that tries to mimic iterators but stay valid as opposite to vector's ones.
void print(const std::string& i)
{
std::cout << "<" << i << "> ";
}
int main()
{
typedef std::vector<std::string> Vector;
Vector v;
v.push_back("H");
v.push_back("E");
v.push_back("W");
StrongIterator<Vector> it0(v, 0);
StrongIterator<Vector> it3(v, v.end());
std::for_each(it0.it(), it3.it(), print);
std::cout << std::endl;
v.push_back("O");
std::for_each(it0.it(), it3.it(), print);
std::cout << *it0;
std::cout << it0->c_str();
return 0;
}
And the iterator itself.
template <typename TVector>
class StrongIterator
{
public:
typedef typename TVector::iterator iterator;
typedef typename TVector::size_type size_type;
typedef typename TVector::value_type value_type;
StrongIterator(TVector& vector,
size_type index):
vector_(vector),
index_(index)
{}
StrongIterator(TVector& vector,
iterator it):
vector_(vector),
index_(std::distance(vector.begin(), it))
{}
iterator it()
{
iterator it = vector_.begin();
std::advance(it, index_);
return it;
}
value_type& operator*()
{
return vector_[index_];
}
value_type* operator->()
{
return &vector_[index_];
}
private:
TVector& vector_;
size_type index_;
};
Unfortunately, once you modify the vector, the iterators that would "point" to an element of the vector are no longer guaranteed to be valid. The only STL structure that I know of which will keep the iterators valid even as the structure is changing is the list<>. If you only want sequential iteration of your structures than you can use std::list<> otherwise I do not know of any other library that can help you; that doesn't mean there isn't one.
Here's some clear documentation on std::list : http://www.cplusplus.com/reference/stl/list/
Using boost::iterator_facade :
// Warning: Untested, not even compiled
template<class VectorT>
class VectorIndex :
public boost::iterator_facade<VectorIndex, typename VectorT::reference, boost::random_access_traversal_tag>
{
public:
VectorIndex(VectorT& Vec, typename VectorT::size_type Index)
: m_Vec(Vec), m_Index(Index)
{
}
private:
friend class boost::iterator_core_access;
void increment()
{
++m_Index;
}
void decrement()
{
--m_Index;
}
void advance(difference_type N)
{
m_Index += N;
}
difference_type distance_to(const VectorIndex& Other)
{
assert(&this->m_Vec == &Other.m_Vec);
return Other.m_Index = this->m_Index;
}
bool equal(const VectorIndex& Other)const
{
return (this->m_Vec == Other.m_Vec)
&& (this->m_Index == Other.m_Index);
}
VectorT::reference dereference() const
{
return m_Vec[m_Index];
}
VectorT m_Vec;
VectorT::size_type m_Index;
};
Unless you write your own version of vector and smart pointer there is no way that a pointer will be valid after a reallocation. If you had your own implementations the smart vector could send notifications to your smart pointers.
However I think that the whole scenario is a bad design and you might be better of redesigning your scenario so that you don't have a requirement like that.
Depending on your use pattern, a std::deque may fufil your requirements. Pointers into a deque are only invalidated if you insert or delete items not at the beginning or end - in pother words push_front() and push_back() don't invalidate pointers into the deque, but other changes do. You get basically the same interface as a vector, but of course the underlying storage is not contiguous.