static_cast and std::vector

Discussion in 'C++' started by john, Jan 20, 2012.

  1. john

    john Guest

    Hi,

    I am attempting to replace lots of C-style casts with static_cast's in
    our code base. Most of these are simple, but there are a few that I'm
    not sure what to do.

    Basically, the problem is shown in the code below. GetD0/GetD1 are the
    original C-style casts that work fine. I would like to change these to
    C++ style casts, but the GetDD0/GetDD1 functions do not compile.

    Is there a way to do this? Are there any potential problems I should be
    aware of?

    Thanks.

    #include <vector>

    class Base {};
    class Derived0 : public Base {};
    class Derived1 : public Base {};

    class Y
    {
    std::vector<Base*> m_vb[2];

    public:

    void Add(Derived0* d0) { m_vb[0].push_back(d0); }
    void Add(Derived1* d1) { m_vb[1].push_back(d1); }

    const std::vector<Derived0*>* GetD0()
    { return (const std::vector<Derived0*>*) &m_vb[0]; }
    const std::vector<Derived1*>* GetD1()
    { return (const std::vector<Derived1*>*) &m_vb[1]; }

    const std::vector<Derived0*>* GetDD0()
    { return static_cast<const std::vector<Derived0*>*>(&m_vb[0]); }
    const std::vector<Derived1*>* GetDD1()
    { return static_cast<const std::vector<Derived1*>*>(&m_vb[1]); }

    };
     
    john, Jan 20, 2012
    #1
    1. Advertising

  2. john

    john Guest

    On 1/20/2012 9:00 AM, Leigh Johnston wrote:
    > On 20/01/2012 13:56, john wrote:
    >> Hi,
    >>
    >> I am attempting to replace lots of C-style casts with static_cast's in
    >> our code base. Most of these are simple, but there are a few that I'm
    >> not sure what to do.
    >>
    >> Basically, the problem is shown in the code below. GetD0/GetD1 are the
    >> original C-style casts that work fine. I would like to change these to
    >> C++ style casts, but the GetDD0/GetDD1 functions do not compile.
    >>
    >> Is there a way to do this? Are there any potential problems I should be
    >> aware of?
    >>
    >> Thanks.
    >>
    >> #include <vector>
    >>
    >> class Base {};
    >> class Derived0 : public Base {};
    >> class Derived1 : public Base {};
    >>
    >> class Y
    >> {
    >> std::vector<Base*> m_vb[2];
    >>
    >> public:
    >>
    >> void Add(Derived0* d0) { m_vb[0].push_back(d0); }
    >> void Add(Derived1* d1) { m_vb[1].push_back(d1); }
    >>
    >> const std::vector<Derived0*>* GetD0()
    >> { return (const std::vector<Derived0*>*) &m_vb[0]; }
    >> const std::vector<Derived1*>* GetD1()
    >> { return (const std::vector<Derived1*>*) &m_vb[1]; }
    >>
    >> const std::vector<Derived0*>* GetDD0()
    >> { return static_cast<const std::vector<Derived0*>*>(&m_vb[0]); }
    >> const std::vector<Derived1*>* GetDD1()
    >> { return static_cast<const std::vector<Derived1*>*>(&m_vb[1]); }
    >>
    >> };

    >
    > Both the C-style cast and the static_cast are wrong; you cannot cast a
    > std::vector<base*> to a std::vector<derived*>.
    >
    > Instead have these getter functions return a std::vector<base*> and
    > downcast (using static_cast or dynamic_cast) the vector's elements
    > instead elsewhere in your code.
    >
    > /Leigh



    I do not see why the C-style cast is wrong. It works flawlessly across
    a wide range of compilers and systems. I can understand the problem
    with C++ static_cast, but I was hoping there was a way around it. If
    there is not a valid C++ way to do this, I'll leave it as is.
     
    john, Jan 20, 2012
    #2
    1. Advertising

  3. john

    john Guest

    >>>
    >>> Both the C-style cast and the static_cast are wrong; you cannot cast a
    >>> std::vector<base*> to a std::vector<derived*>.
    >>>
    >>> Instead have these getter functions return a std::vector<base*> and
    >>> downcast (using static_cast or dynamic_cast) the vector's elements
    >>> instead elsewhere in your code.
    >>>
    >>> /Leigh

    >>
    >>
    >> I do not see why the C-style cast is wrong. It works flawlessly across a
    >> wide range of compilers and systems. I can understand the problem with
    >> C++ static_cast, but I was hoping there was a way around it. If there is
    >> not a valid C++ way to do this, I'll leave it as is.

    >
    > Just because something "works" does not means that it is "correct". The
    > language allows you to perform the C style cast (or reinterpret_cast)
    > however *using* the resultant object reference by invoking a std::vector
    > member function results in undefined behaviour. Undefined behaviour can
    > "silently work" on a particular implementation but that does not mean it
    > is correct; it isn't, it is a bug. The basic reason why this is the case
    > here is due to the fact that std::vector<base*> and
    > std::vector<derived*> are unrelated types.
    >


    Ok. Thanks for the explanation. I may look into fixing this according
    to your suggestion.

    John
     
    john, Jan 20, 2012
    #3
  4. "john" wrote in message news:jfbveg$ae0$...
    >
    >On 1/20/2012 9:00 AM, Leigh Johnston wrote:
    >> On 20/01/2012 13:56, john wrote:
    >>> Hi,
    >>>
    >>> I am attempting to replace lots of C-style casts with static_cast's in
    >>> our code base. Most of these are simple, but there are a few that I'm
    >>> not sure what to do.
    >>>
    >>> Basically, the problem is shown in the code below. GetD0/GetD1 are the
    >>> original C-style casts that work fine. I would like to change these to
    >>> C++ style casts, but the GetDD0/GetDD1 functions do not compile.
    >>>
    >>> Is there a way to do this? Are there any potential problems I should be
    >>> aware of?
    >>>
    >>> Thanks.
    >>>
    >>> #include <vector>
    >>>
    >>> class Base {};
    >>> class Derived0 : public Base {};
    >>> class Derived1 : public Base {};
    >>>
    >>> class Y
    >>> {
    >>> std::vector<Base*> m_vb[2];
    >>>
    >>> public:
    >>>
    >>> void Add(Derived0* d0) { m_vb[0].push_back(d0); }
    >>> void Add(Derived1* d1) { m_vb[1].push_back(d1); }
    >>>
    >>> const std::vector<Derived0*>* GetD0()
    >>> { return (const std::vector<Derived0*>*) &m_vb[0]; }
    >>> const std::vector<Derived1*>* GetD1()
    >>> { return (const std::vector<Derived1*>*) &m_vb[1]; }
    >>>
    >>> const std::vector<Derived0*>* GetDD0()
    >>> { return static_cast<const std::vector<Derived0*>*>(&m_vb[0]); }
    >>> const std::vector<Derived1*>* GetDD1()
    >>> { return static_cast<const std::vector<Derived1*>*>(&m_vb[1]); }
    >>>
    >>> };

    >>
    >> Both the C-style cast and the static_cast are wrong; you cannot cast a
    >> std::vector<base*> to a std::vector<derived*>.
    >>
    >> Instead have these getter functions return a std::vector<base*> and
    >> downcast (using static_cast or dynamic_cast) the vector's elements
    >> instead elsewhere in your code.
    >>
    >> /Leigh

    >
    >
    >I do not see why the C-style cast is wrong. It works flawlessly across a
    >wide range of compilers and systems.


    It may work in the case of simple inheritance, but it usually fails when
    multiple and/or virtual inheritance is going to be used.
     
    Fred Zwarts \(KVI\), Jan 20, 2012
    #4
  5. john <> wrote:
    > I do not see why the C-style cast is wrong.


    Because it's bypassing the language's type checking mechanism, and in
    this case doing so in a manner that's potentially hazardous.

    std::vector<A*> and std::vector<B*> are two completely different and
    independent classes that have no relation to each other (just because
    they are created from the same *template* doesn't make them related;
    the template is used by the compiler to create two different classes).
    In principle it would be possible for the two classes to even have
    completely different implementations (via template specialization).

    More importantly, though, it's theoretically possible for
    sizeof(A*) and sizeof(B*) to be different, which would immediately
    break any code that assumed to have a std::vector<A*> but is in
    reality given a std::vector<B*>.

    That's the reason why static_cast won't allow you to do that: It's
    a safer type checking mechanism than the C style cast (which is
    basically a reinterpret_cast).

    > It works flawlessly across
    > a wide range of compilers and systems.


    If you make this code only for yourself and know how the underlying
    system works, then you could bypass the type checking meachanism as
    you did, as long as you understand why it's wrong in principle.
     
    Juha Nieminen, Jan 20, 2012
    #5
  6. On Jan 20, 8:02 am, Leigh Johnston <> wrote:
    > On 20/01/2012 15:48, Fred Zwarts (KVI) wrote:
    >
    > > "john" wrote in messagenews:jfbveg$ae0$...

    >
    > >> On 1/20/2012 9:00 AM, Leigh Johnston wrote:
    > >>> On 20/01/2012 13:56, john wrote:


    > >>> Both the C-style cast and the static_cast are wrong; you cannot cast a
    > >>> std::vector<base*> to a std::vector<derived*>.

    >
    > >> I do not see why the C-style cast is wrong. It works flawlessly across
    > >> a wide range of compilers and systems.

    >
    > > It may work in the case of simple inheritance, but it usually fails when
    > > multiple and/or virtual inheritance is going to be used.

    >
    > This is not "simple inheritance" as the types involved are unrelated.


    Fred Zwarts meant to say that if the contained types have a simple
    inheritance relationship, then as a matter of coincidence and facts of
    implementations, it's likely to work (even UB programs can work in
    some cases), but if the contained types are multiple or virtual
    inheritance, then it starts becoming much less likely. He did not mean
    to imply the vectors are related by inheritance, nor that the casting
    of the OP is not UB, nor that writing UB code is sound advice.
     
    Joshua Maurice, Jan 20, 2012
    #6
  7. john <> wrote:
    > Hi,
    >
    > I am attempting to replace lots of C-style casts with static_cast's in
    > our code base. Most of these are simple, but there are a few that I'm not sure what to do.
    >
    > Basically, the problem is shown in the code below. GetD0/GetD1 are the
    > original C-style casts that work fine. I would like to change these to
    > C++ style casts, but the GetDD0/GetDD1 functions do not compile.
    >
    > Is there a way to do this? Are there any potential problems I should be aware of?
    >
    > Thanks.
    >
    > #include <vector>
    >
    > class Base {};
    > class Derived0 : public Base {};
    > class Derived1 : public Base {};
    >
    > class Y
    > {
    > std::vector<Base*> m_vb[2];
    >
    > public:
    >
    > void Add(Derived0* d0) { m_vb[0].push_back(d0); }
    > void Add(Derived1* d1) { m_vb[1].push_back(d1); }
    >
    > const std::vector<Derived0*>* GetD0()
    > { return (const std::vector<Derived0*>*) &m_vb[0]; }
    > const std::vector<Derived1*>* GetD1()
    > { return (const std::vector<Derived1*>*) &m_vb[1]; }
    >
    > const std::vector<Derived0*>* GetDD0()
    > { return static_cast<const std::vector<Derived0*>*>(&m_vb[0]); }
    > const std::vector<Derived1*>* GetDD1()
    > { return static_cast<const std::vector<Derived1*>*>(&m_vb[1]); }
    >
    > };


    Why don't you just write:
    std::vector<Derived0*> m_vd0;
    std::vector<Derived1*> m_vd1;
    and use those without any casting?

    This would be the most obvious solution and you are losing nothing.

    Tobi
     
    Tobias Müller, Jan 21, 2012
    #7
  8. john

    Pavel Guest

    john wrote:
    > Hi,
    >
    > I am attempting to replace lots of C-style casts with static_cast's in our code
    > base. Most of these are simple, but there are a few that I'm not sure what to do.
    >
    > Basically, the problem is shown in the code below. GetD0/GetD1 are the original
    > C-style casts that work fine. I would like to change these to C++ style casts,
    > but the GetDD0/GetDD1 functions do not compile.
    >
    > Is there a way to do this? Are there any potential problems I should be aware of?
    >
    > Thanks.
    >
    > #include <vector>
    >
    > class Base {};
    > class Derived0 : public Base {};
    > class Derived1 : public Base {};
    >
    > class Y
    > {
    > std::vector<Base*> m_vb[2];
    >
    > public:
    >
    > void Add(Derived0* d0) { m_vb[0].push_back(d0); }
    > void Add(Derived1* d1) { m_vb[1].push_back(d1); }
    >
    > const std::vector<Derived0*>* GetD0()
    > { return (const std::vector<Derived0*>*) &m_vb[0]; }
    > const std::vector<Derived1*>* GetD1()
    > { return (const std::vector<Derived1*>*) &m_vb[1]; }
    >
    > const std::vector<Derived0*>* GetDD0()
    > { return static_cast<const std::vector<Derived0*>*>(&m_vb[0]); }
    > const std::vector<Derived1*>* GetDD1()
    > { return static_cast<const std::vector<Derived1*>*>(&m_vb[1]); }
    >
    > };
    >


    Technically, C-style cast in this case is reinterpret_cast<>, not static_cast<>
    so you have to be able to compile after converting to reinterpret_cast<>.

    (I know the resulting code will stay UB and that two UBs are theoretically never
    equal; but from practical perspective I would bet old and new UBs will not be
    too different; and quite possible, new code will continue "work fine" in the
    same situations as the old code did).

    -Pavel
     
    Pavel, Jan 22, 2012
    #8
  9. john

    john Guest

    >> #include<vector>
    >>
    >> class Base {};
    >> class Derived0 : public Base {};
    >> class Derived1 : public Base {};
    >>
    >> class Y
    >> {
    >> std::vector<Base*> m_vb[2];
    >>
    >> public:
    >>
    >> void Add(Derived0* d0) { m_vb[0].push_back(d0); }
    >> void Add(Derived1* d1) { m_vb[1].push_back(d1); }
    >>
    >> const std::vector<Derived0*>* GetD0()
    >> { return (const std::vector<Derived0*>*)&m_vb[0]; }
    >> const std::vector<Derived1*>* GetD1()
    >> { return (const std::vector<Derived1*>*)&m_vb[1]; }
    >>
    >> const std::vector<Derived0*>* GetDD0()
    >> { return static_cast<const std::vector<Derived0*>*>(&m_vb[0]); }
    >> const std::vector<Derived1*>* GetDD1()
    >> { return static_cast<const std::vector<Derived1*>*>(&m_vb[1]); }
    >>
    >> };

    >
    > Why don't you just write:
    > std::vector<Derived0*> m_vd0;
    > std::vector<Derived1*> m_vd1;
    > and use those without any casting?
    >
    > This would be the most obvious solution and you are losing nothing.


    We have looked into this, but we also really need functionality like

    const std::vector<Base*>* GetBase(int which)
    { return &m_vb[which]; }

    So, changing as you suggested would preclude this. Would it be possible
    to replace the UB casts

    const std::vector<Derived0*>* GetD0()
    { return (const std::vector<Derived0*>*)&m_vb[0]; }
    const std::vector<Derived1*>* GetD1()
    { return (const std::vector<Derived1*>*)&m_vb[1]; }

    with some type of specialized iterator?

    Thanks.
     
    john, Jan 23, 2012
    #9
  10. john

    Ian Collins Guest

    On 01/24/12 06:47 AM, john wrote:
    >>> #include<vector>
    >>>
    >>> class Base {};
    >>> class Derived0 : public Base {};
    >>> class Derived1 : public Base {};
    >>>
    >>> class Y
    >>> {
    >>> std::vector<Base*> m_vb[2];
    >>>
    >>> public:
    >>>
    >>> void Add(Derived0* d0) { m_vb[0].push_back(d0); }
    >>> void Add(Derived1* d1) { m_vb[1].push_back(d1); }
    >>>
    >>> const std::vector<Derived0*>* GetD0()
    >>> { return (const std::vector<Derived0*>*)&m_vb[0]; }
    >>> const std::vector<Derived1*>* GetD1()
    >>> { return (const std::vector<Derived1*>*)&m_vb[1]; }
    >>>
    >>> const std::vector<Derived0*>* GetDD0()
    >>> { return static_cast<const std::vector<Derived0*>*>(&m_vb[0]); }
    >>> const std::vector<Derived1*>* GetDD1()
    >>> { return static_cast<const std::vector<Derived1*>*>(&m_vb[1]); }
    >>>
    >>> };

    >>
    >> Why don't you just write:
    >> std::vector<Derived0*> m_vd0;
    >> std::vector<Derived1*> m_vd1;
    >> and use those without any casting?
    >>
    >> This would be the most obvious solution and you are losing nothing.

    >
    > We have looked into this, but we also really need functionality like
    >
    > const std::vector<Base*>* GetBase(int which)
    > { return&m_vb[which]; }
    >
    > So, changing as you suggested would preclude this. Would it be possible
    > to replace the UB casts
    >
    > const std::vector<Derived0*>* GetD0()
    > { return (const std::vector<Derived0*>*)&m_vb[0]; }
    > const std::vector<Derived1*>* GetD1()
    > { return (const std::vector<Derived1*>*)&m_vb[1]; }
    >
    > with some type of specialized iterator?


    What do you do with the returned vectors?

    You don't have a vector of Derived0* to return, which is why others have
    told you the casts are UB. If you are iterating through them, you could
    add a (template) method to perform the iteration with the appropriate
    cast of the vector elements (not the vector) to your container class.

    --
    Ian Collins
     
    Ian Collins, Jan 23, 2012
    #10
    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. Anonymous
    Replies:
    20
    Views:
    4,427
    Pete Becker
    Mar 30, 2005
  2. Jason Heyes
    Replies:
    8
    Views:
    767
    Andrew Koenig
    Jan 15, 2006
  3. Bo Peng
    Replies:
    11
    Views:
    1,118
    Victor Bazarov
    Oct 20, 2006
  4. Replies:
    9
    Views:
    1,441
    Nate Barney
    Nov 14, 2006
  5. junyangzou
    Replies:
    13
    Views:
    289
Loading...

Share This Page