Initializing a vector with pointers to elements of another

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Matthias

    #1

    Initializing a vector with pointers to elements of another

    Hi,

    say I have a vector v1:

    std::vector<Som eType> v1;

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

    std::vector<Som eType*> v2;

    std::vector<Som eType>::iterato r 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.

    --
    Regards,
    Matthias
  • Mike Wahler

    #2
    Re: Initializing a vector with pointers to elements of another

    "Matthias" <nospam@digital raid.com> wrote in message
    news:cu8nli$rm0 $01$1@news.t-online.com...[color=blue]
    > Hi,
    >
    > say I have a vector v1:
    >
    > std::vector<Som eType> v1;
    >
    > and I need a vector v2 of pointers to v1's elements:
    >
    > std::vector<Som eType*> v2;
    >
    > std::vector<Som eType>::iterato r 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.[/color]

    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::vecto r<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(v ec.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_inser ter(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


    Comment

    • red floyd

      #3
      Re: Initializing a vector with pointers to elements of another

      Matthias wrote:[color=blue]
      > Hi,
      >
      > say I have a vector v1:
      >
      > std::vector<Som eType> v1;
      >
      > and I need a vector v2 of pointers to v1's elements:
      >
      > std::vector<Som eType*> v2;
      >
      > std::vector<Som eType>::iterato r 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.
      >[/color]

      struct addressor {
      SomeType* operator()(Some Type& s) const { return &s; }
      const SomeType* operator()(cons t SomeType& s) const { return &s; }
      };

      /// ...

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

      Comment

      • red floyd

        #4
        Re: Initializing a vector with pointers to elements of another

        red floyd wrote:[color=blue]
        > Matthias wrote:
        >[color=green]
        >> Hi,
        >>
        >> say I have a vector v1:
        >>
        >> std::vector<Som eType> v1;
        >>
        >> and I need a vector v2 of pointers to v1's elements:
        >>
        >> std::vector<Som eType*> v2;
        >>
        >> std::vector<Som eType>::iterato r 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.
        >>[/color]
        >
        > struct addressor {
        > SomeType* operator()(Some Type& s) const { return &s; }
        > const SomeType* operator()(cons t SomeType& s) const { return &s; }
        > };
        >
        > /// ...
        >
        > std::transform( v1.begin(), v1.end(),
        > std::back_inser ter(v2),
        > addressor());
        >[/color]

        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<SomeTy pe>::size_type> v2;

        for (std::vector<So meType>::size_t ype> i = 0 ; i < v1.size(); ++i)
        v2.push_back(i) ;


        Comment

        • Matthias

          #5
          Re: Initializing a vector with pointers to elements of another

          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.programmin g 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?

          --
          Regards,
          Matthias

          Comment

          • msalters

            #6
            Re: Initializing a vector with pointers to elements of another


            Matthias wrote:[color=blue]
            > 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[/color]
            themselves[color=blue]
            > for performance reasons. At least that's what the guys over at
            > comp.programmin g suggested.[/color]

            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.
            [color=blue]
            > Is it worth the inconvenience at all to sort pointers to path objects[/color]
            [color=blue]
            > instead of sorting the pathS themselves? How expensive is it to copy[/color]
            a[color=blue]
            > path object?[/color]

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

            HTH,
            Michiel Salters

            Comment

            • Matthias

              #7
              Re: Initializing a vector with pointers to elements of another

              msalters wrote:[color=blue]
              > Matthias wrote:
              >[color=green]
              >>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[/color]
              >
              > themselves
              >[color=green]
              >>for performance reasons. At least that's what the guys over at
              >>comp.programm ing suggested.[/color]
              >
              >
              > 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.
              >
              >[color=green]
              >>Is it worth the inconvenience at all to sort pointers to path objects[/color]
              >
              >[color=green]
              >>instead of sorting the pathS themselves? How expensive is it to copy[/color]
              >
              > a
              >[color=green]
              >>path object?[/color]
              >
              >
              > Doesn't matter much, the price of swaps tends to dominate.
              >
              > HTH,
              > Michiel Salters
              >[/color]

              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?

              --
              Regards,
              Matthias

              Comment

              Working...