referring contents of another container.

T

toton

Hi,
I am facing problem some times, and not finding a suitable answer to
solve it.
I have a vector (or some other container, sometimes) of some class,
named CC
like vector<CC> v, NOT vector<CC*> ;

I want another class say Segment to refer a portion of this vector. I
can't store the iterator for vector as a member function to the class,
as
1) The iterators have different invalidation strategy, and may
invalidate the stored iterators when some new elements are added to the
vector.
2) The iterators are not default constructible, where I need to
calculate the range after Segment class is formed.

Someone suggested, storing raw index of the position, as size_t, and
construct iterator from that. But that looks little error prone.

Things are much easy if I use vector<shared_ptr<CC> > rather than
vector<CC> , where I can copy a portion of the vector inside Segment,
as it copies only the pointers (Which looks much like Java collections,
list, subList etc ). However, I want the vector to store CC directly
like vector<CC>,
and Segment to use a reference of the portion (like
vector<shared_ptr<CC> > , as vector<CC&> is not possible , or vector
<CC*> also not possible as the elements in a vector are movable and may
invalidate the pointer , or use iterators).

In actual case, lots of different hierarchical views are associated
with the vector<CC> all of them points to a range in the vector.
Hope, the problem statement is understandable. If needed, I will be
able to supply more detail.
Looking for an elegant solution.
Thanks in advance.
abir
 
G

Gianni Mariani

toton wrote:
....
Looking for an elegant solution.

Have you considered using a std::list ?

There is also another container posted by Martin Knoblauch on
comp.std.c++ recently that may be better.
 
B

benben

toton said:
Hi,
I am facing problem some times, and not finding a suitable answer to
solve it.
I have a vector (or some other container, sometimes) of some class,
named CC
like vector<CC> v, NOT vector<CC*> ;

I want another class say Segment to refer a portion of this vector. I
can't store the iterator for vector as a member function to the class,
as
1) The iterators have different invalidation strategy, and may
invalidate the stored iterators when some new elements are added to the
vector.
2) The iterators are not default constructible, where I need to
calculate the range after Segment class is formed.


What's wrong with:

vector<CC> v(10);

vector<CC*> v_ref;
v_ref.push_back(&v[2]);
v_ref.push_back(&v[3]);
v_ref.push_back(&v[4]);

v_ref[0]->some_CC_memfun();

Notice that the all CC objects are owned by v. v_ref merely references
some of the elements assuming the pointers are valid within its
(v_ref's) life time.

Regards,
Ben
 
T

toton

benben said:
toton said:
Hi,
I am facing problem some times, and not finding a suitable answer to
solve it.
I have a vector (or some other container, sometimes) of some class,
named CC
like vector<CC> v, NOT vector<CC*> ;

I want another class say Segment to refer a portion of this vector. I
can't store the iterator for vector as a member function to the class,
as
1) The iterators have different invalidation strategy, and may
invalidate the stored iterators when some new elements are added to the
vector.
2) The iterators are not default constructible, where I need to
calculate the range after Segment class is formed.


What's wrong with:

vector<CC> v(10);

vector<CC*> v_ref;
v_ref.push_back(&v[2]);
v_ref.push_back(&v[3]);
v_ref.push_back(&v[4]);

v_ref[0]->some_CC_memfun();

Notice that the all CC objects are owned by v. v_ref merely references
some of the elements assuming the pointers are valid within its
(v_ref's) life time.
Thanks. This is very much what I need.
But the questions are,
If v resizes (and increases) , and hence moves the elements whether
still v_ref will have a reference ? Is it true for any other container?
I know that instead of v_ref, If I store iterator begin_ = v.begin()+1
and, iterator end_ = v.begin()+3; they are no more valid when v
resizes, and increases size.
And instead of manual pushback like this, is there a way to use std
copy algorithm which will copy the pointers ?
 
D

dasjotre

toton said:
benben said:
toton said:
Hi,
I am facing problem some times, and not finding a suitable answer to
solve it.
I have a vector (or some other container, sometimes) of some class,
named CC
like vector<CC> v, NOT vector<CC*> ;

I want another class say Segment to refer a portion of this vector. I
can't store the iterator for vector as a member function to the class,
as
1) The iterators have different invalidation strategy, and may
invalidate the stored iterators when some new elements are added to the
vector.
2) The iterators are not default constructible, where I need to
calculate the range after Segment class is formed.


What's wrong with:

vector<CC> v(10);

vector<CC*> v_ref;
v_ref.push_back(&v[2]);
v_ref.push_back(&v[3]);
v_ref.push_back(&v[4]);

v_ref[0]->some_CC_memfun();

Notice that the all CC objects are owned by v. v_ref merely references
some of the elements assuming the pointers are valid within its
(v_ref's) life time.
Thanks. This is very much what I need.
But the questions are,
If v resizes (and increases) , and hence moves the elements whether
still v_ref will have a reference ? Is it true for any other container?
I know that instead of v_ref, If I store iterator begin_ = v.begin()+1
and, iterator end_ = v.begin()+3; they are no more valid when v
resizes, and increases size.

deque is closest to vector and may be implemented
the same.

Better solution is to use list or, if the problem
fits, ::boost::multi_index instead.
And instead of manual pushback like this, is there a way to use std
copy algorithm which will copy the pointers ?

You can do that with transform and something like:

template<class T>
T * ptr_of(T & t){ return &t; }

template<class It1, class It2>
void transform_to_ptr(It1 begin, It1 end, It2 out)
{
::std::transform
( begin, end, out
, ::boost::bind( &ptr_of<typename It1::value_type>, _1)
);
}

void sampl()
{
::std::vector<int> v;
::std::fill_n( ::std::back_inserter(v), 100, 10);

::std::vector<int*> v1;
transform_to_ptr( v.begin(), v.end(), ::std::back_inserter(v1) );
}

 
B

benben

toton said:
benben said:
toton said:
Hi,
I am facing problem some times, and not finding a suitable answer to
solve it.
I have a vector (or some other container, sometimes) of some class,
named CC
like vector<CC> v, NOT vector<CC*> ;

I want another class say Segment to refer a portion of this vector. I
can't store the iterator for vector as a member function to the class,
as
1) The iterators have different invalidation strategy, and may
invalidate the stored iterators when some new elements are added to the
vector.
2) The iterators are not default constructible, where I need to
calculate the range after Segment class is formed.

What's wrong with:

vector<CC> v(10);

vector<CC*> v_ref;
v_ref.push_back(&v[2]);
v_ref.push_back(&v[3]);
v_ref.push_back(&v[4]);

v_ref[0]->some_CC_memfun();

Notice that the all CC objects are owned by v. v_ref merely references
some of the elements assuming the pointers are valid within its
(v_ref's) life time.
Thanks. This is very much what I need.
But the questions are,
If v resizes (and increases) , and hence moves the elements whether
still v_ref will have a reference ? Is it true for any other container?
I know that instead of v_ref, If I store iterator begin_ = v.begin()+1
and, iterator end_ = v.begin()+3; they are no more valid when v
resizes, and increases size.

I hope I understand your problem. It is true that once v moves the
elements the pointers in v_ref will no-longer be valid. But there is not
much you can do because generally you can't have a pointer that points
to a moving object.

Iterators, much like pointers, are also invalidated if you make
insertion or erasure to the vector. Sometimes vectors move objects when
it wants to resize.

If you only want to reference a range, you can use the index:

template <typename C>
class segment
{
public:
typedef typename C::size_type size_type;
typedef typename C::iterator iterator;
typedef typename C::const_iterator const_iterator;
// ...

private:
size_type lower, upper;
C& container;

public:
explicit segment(C& c, size_type l, size_type u)
: container(c), lower(l), upper(u){}

iterator begin(){return container.begin()+lower;}
iterator end(){return container.begin() + upper;}

const_iterator begin() const;
const_iterator end() const;

// ...
};

vector<int> v(10);
segment<vector<int> > s(v, 2, 5); // 2nd, 3rd and 4th elements
for_each(s.begin(), s.end(), some_op);

For more daring design you can write your own iterator type that has
range checks...
And instead of manual pushback like this, is there a way to use std
copy algorithm which will copy the pointers ?

Don't know the quickest way but what's in my head is

template <typename T>
T* address_of(T& t){return &t;}

std::transform(v.begin()+2, v.begin()+5, v_ref.begin(), address_of);

Ben
 
T

toton

benben said:
toton said:
benben said:
toton wrote:
Hi,
I am facing problem some times, and not finding a suitable answer to
solve it.
I have a vector (or some other container, sometimes) of some class,
named CC
like vector<CC> v, NOT vector<CC*> ;

I want another class say Segment to refer a portion of this vector. I
can't store the iterator for vector as a member function to the class,
as
1) The iterators have different invalidation strategy, and may
invalidate the stored iterators when some new elements are added to the
vector.
2) The iterators are not default constructible, where I need to
calculate the range after Segment class is formed.

What's wrong with:

vector<CC> v(10);

vector<CC*> v_ref;
v_ref.push_back(&v[2]);
v_ref.push_back(&v[3]);
v_ref.push_back(&v[4]);

v_ref[0]->some_CC_memfun();

Notice that the all CC objects are owned by v. v_ref merely references
some of the elements assuming the pointers are valid within its
(v_ref's) life time.
Thanks. This is very much what I need.
But the questions are,
If v resizes (and increases) , and hence moves the elements whether
still v_ref will have a reference ? Is it true for any other container?
I know that instead of v_ref, If I store iterator begin_ = v.begin()+1
and, iterator end_ = v.begin()+3; they are no more valid when v
resizes, and increases size.

I hope I understand your problem. It is true that once v moves the
elements the pointers in v_ref will no-longer be valid. But there is not
much you can do because generally you can't have a pointer that points
to a moving object.

Iterators, much like pointers, are also invalidated if you make
insertion or erasure to the vector. Sometimes vectors move objects when
it wants to resize.

If you only want to reference a range, you can use the index:

template <typename C>
class segment
{
public:
typedef typename C::size_type size_type;
typedef typename C::iterator iterator;
typedef typename C::const_iterator const_iterator;
// ...

private:
size_type lower, upper;
C& container;

public:
explicit segment(C& c, size_type l, size_type u)
: container(c), lower(l), upper(u){}

iterator begin(){return container.begin()+lower;}
iterator end(){return container.begin() + upper;}

const_iterator begin() const;
const_iterator end() const;

// ...
};

vector<int> v(10);
segment<vector<int> > s(v, 2, 5); // 2nd, 3rd and 4th elements
for_each(s.begin(), s.end(), some_op);

So I came to the same point! . It is my current implementation ! Only
thing in my mind is, to me it looks "too raw", and was not sure if it
is the proper way of doing the thing.
However if it can be done in this way, I will continue using this.
For more daring design you can write your own iterator type that has
range checks...
Some static assert I always include. But may not need a dynamic range
checking, as all of the codes use begin & end only.
Don't know the quickest way but what's in my head is

template <typename T>
T* address_of(T& t){return &t;}

std::transform(v.begin()+2, v.begin()+5, v_ref.begin(), address_of);
So if I use the code, as like you had posted, I do not need the
transform and the address_of (I really fear boost address_of ! )
Just can anyone say the pluses and minuses of the method ? In other way
is it the best possible way ? As you know now, I only need different
views (and sometimes hierarchical) of same data.

A lots of thanks for the answer
abir
 
T

toton

dasjotre said:
toton said:
benben said:
toton wrote:
Hi,
I am facing problem some times, and not finding a suitable answer to
solve it.
I have a vector (or some other container, sometimes) of some class,
named CC
like vector<CC> v, NOT vector<CC*> ;

I want another class say Segment to refer a portion of this vector. I
can't store the iterator for vector as a member function to the class,
as
1) The iterators have different invalidation strategy, and may
invalidate the stored iterators when some new elements are added to the
vector.
2) The iterators are not default constructible, where I need to
calculate the range after Segment class is formed.


What's wrong with:

vector<CC> v(10);

vector<CC*> v_ref;
v_ref.push_back(&v[2]);
v_ref.push_back(&v[3]);
v_ref.push_back(&v[4]);

v_ref[0]->some_CC_memfun();

Notice that the all CC objects are owned by v. v_ref merely references
some of the elements assuming the pointers are valid within its
(v_ref's) life time.
Thanks. This is very much what I need.
But the questions are,
If v resizes (and increases) , and hence moves the elements whether
still v_ref will have a reference ? Is it true for any other container?
I know that instead of v_ref, If I store iterator begin_ = v.begin()+1
and, iterator end_ = v.begin()+3; they are no more valid when v
resizes, and increases size.

deque is closest to vector and may be implemented
the same.

Better solution is to use list or, if the problem
fits, ::boost::multi_index instead.
list is not a good option to me, as I need the frequent random access.
multi_index looks very promising. Will give it a look now, to check if
it fits my need.
You can do that with transform and something like:

template<class T>
T * ptr_of(T & t){ return &t; }

template<class It1, class It2>
void transform_to_ptr(It1 begin, It1 end, It2 out)
{
::std::transform
( begin, end, out
, ::boost::bind( &ptr_of<typename It1::value_type>, _1)
);
}

void sampl()
{
::std::vector<int> v;
::std::fill_n( ::std::back_inserter(v), 100, 10);

::std::vector<int*> v1;
transform_to_ptr( v.begin(), v.end(), ::std::back_inserter(v1) );
}
Thanks for answering.
abir
 
D

dasjotre

toton said:
list is not a good option to me, as I need the frequent random access.
multi_index looks very promising. Will give it a look now, to check if
it fits my need.

you will end up with some sort of 'binary' search
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top