I've got a class, memberlist, that contains a std::list of class memberinfo. These represents the peers on a network.
I use the class to add some functionality to the list.
I want to expose some iterators (begin and end) so that outside code can loop through my internal list and read their data. However, I want to have two ways of doing this - one that includes an element for the localhost, and one that doesn't.
What's a good way to do this?
I could put the local node first, then have like begin(showlocal=false) just give the second element instead of the first. Or someone suggested storing a pair of with the bool saying if it's local or not.
Any suggestions on a good way to do this? I'm not too great on advanced STL stuff yet.
Personally I would approach this in a different way and have your memberinfo have a way of telling you if it's local or not.
That way you're not specialising your collection class due to a specialisation of the contained objects. In fact you could just use a standard std::list<memberinfo>.
E.g.
class memberinfo
{
bool IsLocal( ) const;
}
Then you would choose whether you're interested in local members or not while you're iterating through the contained objects.
E.g.
std::list<memberinfo>::iterator it;
std::list<memberinfo> list;
for ( it = list.begin() ; it != list.end() ; it++ )
{
if ( it->IsLocal() )
{
// blah blah blah
}
else
{
// dum dee dum dee
}
}
As I said in comment to your question, I think your first solution is reasonable. However, I'm not sure that giving a parameter to begin is the best approach for discriminating the two cases. The major problem with this is that you cannot use your full collection (including the localhost member) as a range, meaning that you cannot use Boost.Range algorithms or the C++11 range-based for loop.
A simple solution would be to have two different member functions returning the appropriate range, as a pair of iterators. Boost.Range provides a sub_range class, which seems rather appropriate (you want to return a sub-range of the list of members). Here is a sample code using this approach:
#include <boost/range.hpp>
#include <iostream>
#include <string>
#include <vector>
struct MemberInfo
{
std::string name;
};
class MemberList
{
public:
typedef std::vector<MemberInfo>::iterator iterator;
typedef std::vector<MemberInfo>::const_iterator const_iterator;
MemberList()
: members_{MemberInfo{"local"}, MemberInfo{"foo"}, MemberInfo{"bar"}}
{}
boost::sub_range<std::vector<MemberInfo>> all() // includes localhost
{
return boost::sub_range<std::vector<MemberInfo>>(
members_.begin(), members_.end());
}
boost::sub_range<std::vector<MemberInfo> const> all() const
{
return boost::sub_range<std::vector<MemberInfo> const>(
members_.begin(), members_.end());
}
boost::sub_range<std::vector<MemberInfo>> some() // excludes localhost
{
return boost::sub_range<std::vector<MemberInfo>>(
++members_.begin(), members_.end());
}
boost::sub_range<std::vector<MemberInfo> const> some() const
{
return boost::sub_range<std::vector<MemberInfo> const>(
++members_.begin(), members_.end());
}
private:
std::vector<MemberInfo> members_;
};
Now, you can use either all() or some() depending on whether you want to include local or not, and both can be used as ranges:
int main()
{
MemberList ml;
for (MemberInfo mi : ml.all()) { std::cout << mi.name << '\n'; }
for (MemberInfo mi : ml.some()) { std::cout << mi.name << '\n'; }
}
And of course, you can still use iterators as usual:
std::find_if(ml.all().begin(), ml.all().end(), ...);
If you don't want to leak the fact that your members are stored in a std::vector, you can use any_range, which erases the underlying iterator type.
Related
I'm looking for a C++ container to store pointers to objects which also meets the following requirements.
A container that keeps the order of elements (sequence container, so std::set is not suitable)
A container that has a member function which return the actual size (As std::array::size() always returns the fixed size, std::array is not suitable)
A container that supports random accesses such as operator [].
This is my code snippet and I'd like to remove the assertions used for checking size and uniqueness of elements.
#include <vector>
#include <set>
#include "assert.h"
class Foo {
public:
void DoSomething() {
}
};
int main() {
// a variable used to check whether a container is properly assigned
const uint8_t size_ = 2;
Foo foo1;
Foo foo2;
// Needs a kind of sequential containers to keep the order
// used std::vector instead of std::array to use member function size()
const std::vector<Foo*> vec = {
&foo1,
&foo2
};
std::set<Foo*> set_(vec.begin(), vec.end());
assert(vec.size() == size_); // size checking against pre-defined value
assert(vec.size() == set_.size()); // check for elements uniqueness
// Needs to access elements using [] operator
for (auto i = 0; i < size_; i++) {
vec[i]->DoSomething();
}
return 0;
}
Is there a C++ container which doesn't need two assertions used in my code snippet? Or should I need to make my own class which encapsulates one of STL containers?
So a class that acts like a vector except if you insert, it rejects duplicates like a set or a map.
One option might be the Boost.Bimap with indices of T* and sequence_index.
Your vector-like indexing would be via the sequence_index. You might even be willing to live with holes in the sequence after an element is erased.
Sticking with STLyou could implement a bidirectional map using 2 maps, or the following uses a map and a vector:
Note that by inheriting from vector I get all the vector methods for free, but I also risk the user downcasting to the vector.
One way round that without remodelling with a wrapper (a la queue vs list) is to make it protected inheritance and then explicitly using all the methods back to public. This is actually safer as it ensures you haven't inadvertently left some vector modification method live that would take the two containers out of step.
Note also that you would need to roll your own initializer_list constructor if you wanted one to filter out any duplicates. And you would have to do a bit of work to get this thread-safe.
template <class T>
class uniqvec : public std::vector<T*>
{
private:
typedef typename std::vector<T*> Base;
enum {push_back, pop_back, emplace_back, emplace}; //add anything else you don't like from vector
std::map <T*, size_t> uniquifier;
public:
std::pair<typename Base::iterator, bool> insert(T* t)
{
auto rv1 = uniquifier.insert(std::make_pair(t, Base::size()));
if (rv1.second)
{
Base::push_back(t);
}
return std::make_pair(Base::begin()+rv1.first.second, rv1.second);
}
void erase(T* t)
{
auto found = uniquifier.find(t);
if (found != uniquifier.end())
{
auto index = found->second;
uniquifier.erase(found);
Base::erase(Base::begin()+index);
for (auto& u : uniquifier)
if (u.second > index)
u.second--;
}
}
// Note that c++11 returns the next safe iterator,
// but I don't know if that should be in vector order or set order.
void erase(typename Base::iterator i)
{
return erase(*i);
}
};
As others have mentioned, your particular questions seems like the XY problem (you are down in the weeds about a particular solution instead of focusing on the original problem). There was an extremely useful flowchart provided here a number of years ago (credit to #MikaelPersson) that will help you choose a particular STL container to best fit your needs. You can find the original question here In which scenario do I use a particular STL container?.
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.
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 do I get the position of an element inside a vector, where the elements are classes. Is there a way of doing this?
Example code:
class Object
{
public:
void Destroy()
{
// run some code to get remove self from vector
}
}
In main.cpp:
std::vector<Object> objects;
objects.push_back( <some instances of Object> );
// Some more code pushing back some more stuff
int n = 20;
objects.at(n).Destroy(); // Assuming I pushed back 20 items or more
So I guess I want to be able to write a method or something which is a member of the class which will return the location of itself inside the vector... Is this possible?
EDIT:
Due to confusion, I should explain better.
void Destroy(std::vector<Object>& container){
container.erase( ?...? );
}
The problem is, how can I find the number to do the erasing...? Apparently this isn't possible... I thought it might not be...
You can use std::find to find elements in vector (providing you implement a comparison operator (==) for Object. However, 2 big concerns:
If you need to find elements in a container then you will ger much better performance with using an ordered container such as std::map or std::set (find operations in O(log(N)) vs O(N)
Object should not be the one responsible of removing itself from the container. Object shouldn't know or be concerned with where it is, as that breaks encapsulation. Instead, the owner of the container should concern itself ith such tasks.
The object can erase itself thusly:
void Destroy(std::vector<Object>& container);
{
container.erase(container.begin() + (this - &container[0]));
}
This will work as you expect, but it strikes me as exceptionally bad design. Members should not have knowledge of their containers. They should exist (from their own perspective) in an unidentifiable limbo. Creation and destruction should be left to their creator.
Objects in a vector don't automatically know where they are in the vector.
You could supply each object with that information, but much easier: remove the object from the vector. Its destructor is then run automatically.
Then the objects can be used also in other containers.
Example:
#include <algorithm>
#include <iostream>
#include <vector>
class object_t
{
private:
int id_;
public:
int id() const { return id_; }
~object_t() {}
explicit object_t( int const id ): id_( id ) {}
};
int main()
{
using namespace std;
vector<object_t> objects;
for( int i = 0; i <= 33; ++i )
{
objects.emplace_back( i );
}
int const n = 20;
objects.erase( objects.begin() + n );
for( auto const& o : objects )
{
cout << o.id() << ' ';
}
cout << endl;
}
If you need to destroy the n'th item in a vector then the easiest way is to get an iterator from the beginning using std::begin() and call std::advance() to advance how ever many places you want, so something like:
std::vector<Object> objects;
const size_t n = 20;
auto erase_iter = std::advance(std::begin(objects), n);
objects.erase(erase_iter);
If you want to find the index of an item in a vector then use std::find to get the iterator and call std::distance from the beginning.
So something like:
Object object_to_find;
std::vector<Object> objects;
auto object_iter = std::find(std::begin(objects), std::end(objects), object_to_find);
const size_t n = std::distance(std::begin(objects), object_iter);
This does mean that you need to implement an equality operator for your object. Or you could try something like:
auto object_iter = std::find(std::begin(objects), std::end(objects),
[&object_to_find](const Object& object) -> bool { return &object_to_find == &object; });
Although for this to work the object_to_find needs to be the one from the actual list as it is just comparing addresses.
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.