Initializing a vector with pointers to elements of another

M

Matthias

Hi,

say I have a vector v1:

std::vector<SomeType> v1;

and I need a vector v2 of pointers to v1's elements:

std::vector<SomeType*> v2;

std::vector<SomeType>::iterator iter;
for( iter = v1.begin(); iter != v1.end(), ++iter )
v2.push_back( &(*iter) );


Now is there a more elegant way to initialize v2 instead of looping
through v1 and pushing back the *iter's address to v2?
Something like "for each elem in v1 insert its address into v2"?
Having a loop which only consists of a single insert operation, I have
the feeling this may be better expressed with some STL algo.
 
M

Mike Wahler

Matthias said:
Hi,

say I have a vector v1:

std::vector<SomeType> v1;

and I need a vector v2 of pointers to v1's elements:

std::vector<SomeType*> v2;

std::vector<SomeType>::iterator iter;
for( iter = v1.begin(); iter != v1.end(), ++iter )
v2.push_back( &(*iter) );


Now is there a more elegant way to initialize v2 instead of looping
through v1 and pushing back the *iter's address to v2?
Something like "for each elem in v1 insert its address into v2"?
Having a loop which only consists of a single insert operation, I have
the feeling this may be better expressed with some STL algo.

You could use 'std::for_each()' with a functor, but imo it's
probably not worth the trouble. You might just want to wrap
that loop up into a function with references to the two vectors
as parameters, then just call from your 'main' logic. Here's the
'for_each' code just for fun anyway:


#include <algorithm>
#include <vector>

class ftor
{
std::vector<int*>& v;
public:
ftor(std::vector<int*>& arg) : v(arg)
{
}

void operator()(int& i)
{
v.push_back(&i);
}
};

int main()
{
std::vector<int> vec;
for(int i = 0; i < 5; ++i)
vec.push_back(i);

std::vector<int*> pvec;
std::for_each(vec.begin(), vec.end(), ftor(pvec));

return 0;
}

Another possiblity (if your element type is user-defined), is
to define a conversion from T to T*, and use 'std::copy' (not
possible if the element type is a built-in type):

#include <algorithm>
#include <vector>

class C
{
public:
operator C*()
{
return this;
}
};

int main()
{
std::vector<C> cvec;
for(int i = 0; i < 5; ++i)
{
cvec.push_back(C());
}

std::vector<C*> pvec;

std::copy(cvec.begin(), cvec.end(),
std::back_inserter(pvec));

return 0;
}

However I consider this dangerous, as the automatic conversion
from C to C* could mask errors elsewhere.

Having said all the above, BE WARNED: No matter which way you
store your pointers (with a 'plain' loop, either of the ways
I've shown, or any other way), note that if you later modify
the vector of whose elements you're storing their addresses,
and the vector is later modified, the elements could be moved
due to reallocation, invalidating the address values stored
in the other vector. I'd consider doing what you're
asking about only if the first vector is const (in which
case you'd have to load it via a ctor, since you wouln't
be able to 'push_back' the elements. Or if it's not const,
you'd need to reset and reload the pointer vector every time
the first vector gets changed. An awful lot of work. :)



-Mike
 
R

red floyd

Matthias said:
Hi,

say I have a vector v1:

std::vector<SomeType> v1;

and I need a vector v2 of pointers to v1's elements:

std::vector<SomeType*> v2;

std::vector<SomeType>::iterator iter;
for( iter = v1.begin(); iter != v1.end(), ++iter )
v2.push_back( &(*iter) );


Now is there a more elegant way to initialize v2 instead of looping
through v1 and pushing back the *iter's address to v2?
Something like "for each elem in v1 insert its address into v2"?
Having a loop which only consists of a single insert operation, I have
the feeling this may be better expressed with some STL algo.

struct addressor {
SomeType* operator()(SomeType& s) const { return &s; }
const SomeType* operator()(const SomeType& s) const { return &s; }
};

/// ...

std::transform(v1.begin(), v1.end(),
std::back_inserter(v2),
addressor());
 
R

red floyd

red said:
struct addressor {
SomeType* operator()(SomeType& s) const { return &s; }
const SomeType* operator()(const SomeType& s) const { return &s; }
};

/// ...

std::transform(v1.begin(), v1.end(),
std::back_inserter(v2),
addressor());

That said, storing *addresses* of vector elements is a "bad idea"(tm).
You have the same problem as storing iterators to the elements -- they
can be invalidated should the vector need to reallocate itself.
Better to store the indices instead. i.e.

std::vector<std::vector<SomeType>::size_type> v2;

for (std::vector<SomeType>::size_type> i = 0 ; i < v1.size(); ++i)
v2.push_back(i);
 
M

Matthias

Thanks for your answers.

As to the overall pointer question:
I want to store pointers, because I need to sort the elements, and I
thought I'd be better to sort pointers instead of the objects themselves
for performance reasons. At least that's what the guys over at
comp.programming suggested.

On the other hand, the actual objects are boost pathS, which only
consist of a single string object IIRC (the rest of the path class are
operations).

Is it worth the inconvenience at all to sort pointers to path objects
instead of sorting the pathS themselves? How expensive is it to copy a
path object?
 
M

msalters

Matthias said:
Thanks for your answers.

As to the overall pointer question:
I want to store pointers, because I need to sort the elements, and I
thought I'd be better to sort pointers instead of the objects themselves
for performance reasons. At least that's what the guys over at
comp.programming suggested.

Well, over here we'd say, profile, and optimize only if needed, and
then profile again to check you actually gained something.

The problem is that swapping two T's may be more expensive then
checking two T*s, but this is not always the case. In particular,
swapping two strings or similar objects is often just as expensive:
a common string implementation is just a pointer+size. Swapping those
is twice the work of swapping two pointers, which is balanced by
the reduction in indirection.
Is it worth the inconvenience at all to sort pointers to path objects
instead of sorting the pathS themselves? How expensive is it to copy a
path object?

Doesn't matter much, the price of swaps tends to dominate.

HTH,
Michiel Salters
 
M

Matthias

msalters said:
Well, over here we'd say, profile, and optimize only if needed, and
then profile again to check you actually gained something.

The problem is that swapping two T's may be more expensive then
checking two T*s, but this is not always the case. In particular,
swapping two strings or similar objects is often just as expensive:
a common string implementation is just a pointer+size. Swapping those
is twice the work of swapping two pointers, which is balanced by
the reduction in indirection.




Doesn't matter much, the price of swaps tends to dominate.

HTH,
Michiel Salters

So, there's no reason to sort a list of pointers, because the sort
itself is expensive for both path and "pointer to path"?
Is that what you mean?
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top