Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > static_cast and std::vector

Reply
Thread Tools

static_cast and std::vector

 
 
john
Guest
Posts: n/a
 
      01-20-2012
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]); }

};

 
Reply With Quote
 
 
 
 
john
Guest
Posts: n/a
 
      01-20-2012
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.



 
Reply With Quote
 
 
 
 
john
Guest
Posts: n/a
 
      01-20-2012
>>>
>>> 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
 
Reply With Quote
 
Fred Zwarts \(KVI\)
Guest
Posts: n/a
 
      01-20-2012
"john" wrote in message news:jfbveg$ae0$(E-Mail Removed)...
>
>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.


 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      01-20-2012
john <(E-Mail Removed)> 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.
 
Reply With Quote
 
Joshua Maurice
Guest
Posts: n/a
 
      01-20-2012
On Jan 20, 8:02*am, Leigh Johnston <(E-Mail Removed)> wrote:
> On 20/01/2012 15:48, Fred Zwarts (KVI) wrote:
>
> > "john" wrote in messagenews:jfbveg$ae0$(E-Mail Removed)...

>
> >> 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.
 
Reply With Quote
 
Tobias Müller
Guest
Posts: n/a
 
      01-21-2012
john <(E-Mail Removed)> 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
 
Reply With Quote
 
Pavel
Guest
Posts: n/a
 
      01-22-2012
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
 
Reply With Quote
 
john
Guest
Posts: n/a
 
      01-23-2012
>> #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.



 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      01-23-2012
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
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Is static_cast<int>(static_cast<double>(a)) == a? Bo Peng C++ 11 10-20-2006 12:59 PM
Moving to static_cast and reinterpret_cast from old C-style cast Kobe C++ 3 02-15-2006 08:13 PM
static_cast, inheritance and more. Amit C++ 2 05-17-2005 07:07 PM
static_cast and globally scoped types. Otto Lind C++ 4 03-06-2004 09:28 AM
how static_cast and dynamic_cast implemented? Yuming Ma C++ 1 12-17-2003 12:58 AM



Advertisments