vector <Base *> = vector <Derived *> ??

Discussion in 'C++' started by call_me_anything, Jan 23, 2007.

  1. why is the following not allowed :

    vector <Base *> vec_of_base;
    vector <Derived *> vec_of_derived;
    vec_of_base = vec_of_derived;



    Note : The following is allowed :

    Base *base_ptr;
    Derived *derived_ptr;
    base_ptr = derived_ptr;

    How do things change when we use a vector ?
     
    call_me_anything, Jan 23, 2007
    #1
    1. Advertising

  2. call_me_anything

    Mark P Guest

    call_me_anything wrote:
    > why is the following not allowed :
    >
    > vector <Base *> vec_of_base;
    > vector <Derived *> vec_of_derived;
    > vec_of_base = vec_of_derived;
    >
    >


    Because vector<Derived*> is not derived from vector<Base*>. In fact,
    considering the possibility of template specialization, vector<Derived*>
    may be wildly different than vector<Base*>.

    >
    > Note : The following is allowed :
    >
    > Base *base_ptr;
    > Derived *derived_ptr;
    > base_ptr = derived_ptr;
    >
    > How do things change when we use a vector ?
    >


    It's not unique to a vector. A relation between the template parameters
    does not imply any relationship between the template classes.
     
    Mark P, Jan 23, 2007
    #2
    1. Advertising

  3. "call_me_anything" <> wrote in message
    news:...

    > why is the following not allowed :
    >
    > vector <Base *> vec_of_base;
    > vector <Derived *> vec_of_derived;
    > vec_of_base = vec_of_derived;


    It's hard to understand how one would implement such a feature without also
    allowing

    vector<X> vx;
    vector<Y> vy;

    vx = vy;

    whenever it is possible to convert Y to X. Such assignments could be
    allowed in principle, but they can also be hazardous and inefficient. If
    you want to achieve that effect, you can do so fairly easily:

    vec_of_base.assign(vec_of_derived.begin(), vec_of_derived.end());

    Please note that this question is completely different from the commonly
    asked question about why it is not possible to convert a vector<Derived>* to
    a vector<Base>*.
     
    Andrew Koenig, Jan 23, 2007
    #3
  4. call_me_anything

    Noah Roberts Guest

    Re: vector <Base *> = vector <Derived *> ??

    Andrew Koenig wrote:
    > "call_me_anything" <> wrote in message
    > news:...
    >
    > > why is the following not allowed :
    > >
    > > vector <Base *> vec_of_base;
    > > vector <Derived *> vec_of_derived;
    > > vec_of_base = vec_of_derived;

    >
    > It's hard to understand how one would implement such a feature without also
    > allowing
    >
    > vector<X> vx;
    > vector<Y> vy;
    >
    > vx = vy;
    >
    > whenever it is possible to convert Y to X.


    You could use a combination of enable_if, is_pointer, and
    is_base_of...maybe something like so:

    template < typename other_val_type >
    enable_if
    <
    mpl::and_
    <
    is_pointer<value_type>
    , is_pointer<other_val_type>
    , is_base_of<value_type, other_val_type>
    >

    , vector &
    >

    operator = ( vector<other_val_type> const & right)
    {
    ....??
    }
     
    Noah Roberts, Jan 23, 2007
    #4
  5. call_me_anything

    Pavel Shved Guest

    Re: vector <Base *> = vector <Derived *> ??

    On Jan 23, 8:31 pm, "call_me_anything" <> wrote:
    > why is the following not allowed :
    >
    > vector <Base *> vec_of_base;
    > vector <Derived *> vec_of_derived;
    > vec_of_base = vec_of_derived;
    > ...
    > How do things change when we use a vector ?


    Well, and if we call these types not Base and Derived, having the
    assignment base=derived being correct, will these vectors be equal,
    without derivation relationships? We will have to do element-by-element
    assignment anyway.

    Although in this case there should work a trick, based on the equality
    of Base* and Derived* entities -- they are pointers with same size. I'm
    not quite sure whether it's correct, but i was once told to try
    reinterpret_cast vec_of_base. Though, having been never tried out by
    me, it seems reasonable.
     
    Pavel Shved, Jan 24, 2007
    #5
  6. call_me_anything

    Joe Gottman Guest

    call_me_anything wrote:
    > why is the following not allowed :
    >
    > vector <Base *> vec_of_base;
    > vector <Derived *> vec_of_derived;
    > vec_of_base = vec_of_derived;
    >
    >


    Note that the following is legal:

    vector<Base *> vec_of_base;
    vector<Derived *> vec_of_derived;
    vec_of_base.assign(vec_of_derived.begin(), vec_of_derived.end());

    Admittedly it's much wordier than your version, but it compiles and does
    what you want.

    Joe Gottman
     
    Joe Gottman, Jan 24, 2007
    #6
  7. call_me_anything

    Pavel Shved Guest

    Re: vector <Base *> = vector <Derived *> ??

    > why is the following not allowed :
    >
    > vector <Base *> vec_of_base;
    > vector <Derived *> vec_of_derived;
    > vec_of_base = vec_of_derived;


    I became curious enough to check it for myself.

    vec_of_base=*reinterpret_cast<vector<Base*>*>(&vec_of_derived)

    This does work, at least under MSVS.
     
    Pavel Shved, Jan 24, 2007
    #7
  8. Re: vector <Base *> = vector <Derived *> ??

    "Pavel Shved" <> wrote in message
    news:...

    > I became curious enough to check it for myself.


    > vec_of_base=*reinterpret_cast<vector<Base*>*>(&vec_of_derived)


    > This does work, at least under MSVS.


    If it works, it does so only by coincidence.
     
    Andrew Koenig, Jan 24, 2007
    #8
  9. call_me_anything

    Pavel Shved Guest

    Re: vector <Base *> = vector <Derived *> ??

    On Jan 24, 8:54 am, "Andrew Koenig" <> wrote:
    > > vec_of_base=*reinterpret_cast<vector<Base*>*>(&vec_of_derived)


    > If it works, it does so only by coincidence.


    Yes, coincidence is the exact reason why it does work. ;-) vector
    <Base*> and vector <Derived*> are be byte-to-byte equal.
     
    Pavel Shved, Jan 24, 2007
    #9
  10. call_me_anything

    Noah Roberts Guest

    Re: vector <Base *> = vector <Derived *> ??

    On Jan 23, 1:33 pm, "Noah Roberts" <> wrote:

    > > whenever it is possible to convert Y to X.You could use a combination of enable_if, is_pointer, and

    > is_base_of...maybe something like so:
    >
    > template < typename other_val_type >
    > enable_if
    > <
    > mpl::and_
    > <
    > is_pointer<value_type>
    > , is_pointer<other_val_type>
    > , is_base_of<value_type, other_val_type>
    > >

    > , vector &
    > > // HERE

    > operator = ( vector<other_val_type> const & right)
    > {
    > ...??
    >
    > }


    I don't normally respond to people that email me instead of posting to
    the group but I decided in this case I would. Someone asked me two
    questions:

    1) Are these standard components or did I just make them up?

    It is a combination of standard stuff and things that are found in
    certain boost libraries. Some of it, including the is_pointer and
    is_base_of traits, will be in the next standard. These are basic
    metaprogramming techniques but if you've never seen metaprogramming it
    might be rather difficult to understand.

    2) Where does the last > go?

    Apparently google groups removed it. It should be on the line after
    vector& and before "operator", I put it back.

    Now, newsgroup etiquette says you post your replies to the group, not
    the user. This is not only because it might be considered rude but so
    that others can see the answer...now you know.
     
    Noah Roberts, Jan 24, 2007
    #10
  11. Re: vector <Base *> = vector <Derived *> ??

    * Pavel Shved:
    >
    > On Jan 24, 8:54 am, "Andrew Koenig" <> wrote:
    >>> vec_of_base=*reinterpret_cast<vector<Base*>*>(&vec_of_derived)

    >
    >> If it works, it does so only by coincidence.

    >
    > Yes, coincidence is the exact reason why it does work. ;-) vector
    > <Base*> and vector <Derived*> are be byte-to-byte equal.


    Sorry, that's incorrect.

    One might easily get the impression that these vectors would be
    effectively equal because both are vectors of class type pointers, and
    those pointer values are the same size, and so, unless the vector
    implementation against all odds contains some unwarranted hacking, they
    have the exact same /memory layout/.

    But consider that reinterpret_cast<Base*>(pDerived) and
    static_cast<Base*>(pDerived) do not always yield the same result.

    So what you have is simply undefined behavior.

    If it works, it works by coincidence, for a particular pair of Base and
    Derived classes.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Jan 24, 2007
    #11
  12. call_me_anything

    Daniel T. Guest

    "call_me_anything" <> wrote:

    > why is the following not allowed :
    >
    > vector <Base *> vec_of_base;
    > vector <Derived *> vec_of_derived;
    > vec_of_base = vec_of_derived;
    >
    >
    >
    > Note : The following is allowed :
    >
    > Base *base_ptr;
    > Derived *derived_ptr;
    > base_ptr = derived_ptr;
    >
    > How do things change when we use a vector ?


    Things change because the above doesn't work for arrays, thus it doesn't
    work for vectors. As an example:

    struct Base {
    int x;
    };

    struct Derived : Base {
    int y;
    };

    int main() {
    Derived* derivedPtr = new Derived[2];
    derivedPtr[0].y = 10;
    Base* basePtr = derivedPtr;
    basePtr[1].x = 0;
    assert( derivedPtr[0].y == 10 );
    delete [] derivedPtr;
    }

    The assert in the above will probably fail, even though it shouldn't.

    The fact that the vector code fails to compile is yet another example of
    why vectors are better than bald arrays.
     
    Daniel T., Jan 24, 2007
    #12
  13. Re: vector <Base *> = vector <Derived *> ??

    "Pavel Shved" <> wrote in message
    news:...

    >> If it works, it does so only by coincidence.


    > Yes, coincidence is the exact reason why it does work. ;-) vector
    > <Base*> and vector <Derived*> are be byte-to-byte equal.


    You think so? How about trying it with these classes:

    struct Base { };

    struct Derived: virtual Base { };

    Now the internal representations of a Derived* and a Base* pointing to the
    same object are different.

    As I said, if it works, it does so only by coincidence.
     
    Andrew Koenig, Jan 24, 2007
    #13
  14. "Daniel T." <> wrote in message
    news:...
    > "call_me_anything" <> wrote:
    >
    >> why is the following not allowed :
    >>
    >> vector <Base *> vec_of_base;
    >> vector <Derived *> vec_of_derived;
    >> vec_of_base = vec_of_derived;
    >>
    >>
    >>
    >> Note : The following is allowed :
    >>
    >> Base *base_ptr;
    >> Derived *derived_ptr;
    >> base_ptr = derived_ptr;
    >>
    >> How do things change when we use a vector ?

    >
    > Things change because the above doesn't work for arrays, thus it doesn't
    > work for vectors. As an example:
    >
    > struct Base {
    > int x;
    > };
    >
    > struct Derived : Base {
    > int y;
    > };
    >
    > int main() {
    > Derived* derivedPtr = new Derived[2];
    > derivedPtr[0].y = 10;
    > Base* basePtr = derivedPtr;
    > basePtr[1].x = 0;
    > assert( derivedPtr[0].y == 10 );
    > delete [] derivedPtr;
    > }
    >
    > The assert in the above will probably fail, even though it shouldn't.
    >
    > The fact that the vector code fails to compile is yet another example of
    > why vectors are better than bald arrays.


    This argument would be better if the OP wanted to assign a vector<Derived>
    to a vector<Base>. But he doesn't want that, he wants to assign a
    vector<Derived*> to a vector<Base*>. But aside from that, a vector
    assignment will create a _copy_, so pointer magic has got nothing to do with
    it - you can perfectly copy an array of Deriveds to an array of Base. You
    can't use the assignment operator for it, but std::copy could cope with it
    just fine. Of course, you're slicing the Deriveds, but hey, if that's what
    you want you can get it ;).

    Now, the reason why you can't assign a Derived** to a Base**, is because
    then you could let a Derived* point to something other than a Derived
    (similar with const).
     
    Sylvester Hesp, Jan 24, 2007
    #14
  15. call_me_anything

    Noah Roberts Guest

    Re: vector <Base *> = vector <Derived *> ??

    On Jan 23, 11:00 pm, "Alf P. Steinbach" <> wrote:
    > * Pavel Shved:
    >
    >
    >
    > > On Jan 24, 8:54 am, "Andrew Koenig" <> wrote:
    > >>> vec_of_base=*reinterpret_cast<vector<Base*>*>(&vec_of_derived)

    >
    > >> If it works, it does so only by coincidence.

    >
    > > Yes, coincidence is the exact reason why it does work. ;-) vector
    > > <Base*> and vector <Derived*> are be byte-to-byte equal.Sorry, that's incorrect.

    >
    > One might easily get the impression that these vectors would be
    > effectively equal because both are vectors of class type pointers, and
    > those pointer values are the same size, and so, unless the vector
    > implementation against all odds contains some unwarranted hacking, they
    > have the exact same /memory layout/.
    >
    > But consider that reinterpret_cast<Base*>(pDerived) and
    > static_cast<Base*>(pDerived) do not always yield the same result.
    >


    This is why I didn't fill out the body of my assignment op hack.

    Is this code valid?

    Derived * d = new Derived[20]();
    Base * b = static_cast<Base*>(d);

    b[10]->f();

    delete [] b;

    For all possible constructions of Base and Derived? (assuming a
    parental is-a relation)

    I believe it should be, but in all honesty I've never had to do
    anything remotely like this.
     
    Noah Roberts, Jan 24, 2007
    #15
  16. Re: vector <Base *> = vector <Derived *> ??

    "Noah Roberts" <> wrote in message
    news:...

    > Is this code valid?
    >
    > Derived * d = new Derived[20]();
    > Base * b = static_cast<Base*>(d);
    >
    > b[10]->f();
    >
    > delete [] b;
    >
    > For all possible constructions of Base and Derived? (assuming a
    > parental is-a relation)


    No way.

    It will usually work in practice provided that Base has a virtual destructor
    and sizeof(Base) == sizeof(Derived), but not otherwise. Moreover, it's not
    guaranteed to work in any circumstances.
     
    Andrew Koenig, Jan 24, 2007
    #16
  17. call_me_anything

    Noah Roberts Guest

    Re: vector <Base *> = vector <Derived *> ??

    On Jan 24, 11:23 am, "Andrew Koenig" <> wrote:
    > "Noah Roberts" <> wrote in messagenews:...
    >
    > > Is this code valid?

    >
    > > Derived * d = new Derived[20]();
    > > Base * b = static_cast<Base*>(d);

    >
    > > b[10]->f();

    >
    > > delete [] b;

    >
    > > For all possible constructions of Base and Derived? (assuming a
    > > parental is-a relation)No way.

    >
    > It will usually work in practice provided that Base has a virtual destructor
    > and sizeof(Base) == sizeof(Derived), but not otherwise. Moreover, it's not
    > guaranteed to work in any circumstances.


    Yeah, nm. I knew that. Wasn't thinking clearly. Meant something more
    along the lines of Base ** ptr = static_cast<Base**>(dptr), which is
    not valid at any rate. If there was a way for the vector to swap it's
    buffer pointer with the other vector there might be a benifit to op=
    for base/derived vectors but I don't see that as being reliably
    possible.
     
    Noah Roberts, Jan 24, 2007
    #17
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. CD
    Replies:
    2
    Views:
    806
    Victor Bazarov
    Oct 5, 2004
  2. qazmlp
    Replies:
    1
    Views:
    570
    qazmlp
    Apr 10, 2005
  3. Replies:
    4
    Views:
    410
    Alf P. Steinbach
    May 23, 2007
  4. Replies:
    1
    Views:
    396
    myork
    May 23, 2007
  5. Replies:
    1
    Views:
    389
    Victor Bazarov
    May 23, 2007
Loading...

Share This Page