By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,604 Members | 1,490 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,604 IT Pros & Developers. It's quick & easy.

referring contents of another container.

P: n/a
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<CCv, 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<CCall 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

Nov 13 '06 #1
Share this Question
Share on Google+
8 Replies


P: n/a
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.

Nov 13 '06 #2

P: n/a
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<CCv, 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<CCv(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
Nov 13 '06 #3

P: n/a

benben wrote:
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<CCv, 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<CCv(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 ?
Regards,
Ben
Nov 13 '06 #4

P: n/a

toton wrote:
benben wrote:
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<CCv, 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<CCv(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<intv;
::std::fill_n( ::std::back_inserter(v), 100, 10);

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

Regards,
Ben
Nov 13 '06 #5

P: n/a
toton wrote:
benben wrote:
>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<CCv, 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<CCv(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<intv(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);
>
>Regards,
Ben
Ben
Nov 13 '06 #6

P: n/a

benben wrote:
toton wrote:
benben wrote:
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<CCv, 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<CCv(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<intv(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.
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);
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
Regards,
Ben

Ben
Nov 13 '06 #7

P: n/a

dasjotre wrote:
toton wrote:
benben wrote:
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<CCv, 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<CCv(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.
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<intv;
::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
Regards,
Ben
Nov 13 '06 #8

P: n/a

toton wrote:
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

Nov 13 '06 #9

This discussion thread is closed

Replies have been disabled for this discussion.