Topic: C-style cast vs. static_cast


Author: James Kuyper <kuyper@wizard.net>
Date: 2000/01/13
Raw View
David R Tribble wrote:
> [The example given was casting a pointer to a derived class to a
> pointer to a base class, where the derived class privately inherits
> the base class.
>
>     class Base { ... };
>
>     class Der: private Base { ... };
>
>     void foo(Der *d)
>     {
>         Base *  b;
>
>         b = dynamic_cast<Base *>(d);  // Illegal, Base inaccessible
>         b = (Base *)d;                // Legal
>     }
> ]
>
.....
> I don't mean to question your veracity, but why does a C-style cast
> return well-defined results, while a reinterpret_cast returns
> undefined results (in this situation)?

Not undefined, but implementation-defined. Using the
implementation-defined result for any purpose except to convert it back
to it's original type is what would allow undefined behavior.

>     b = reinterpret_cast<Base *>(d);  // Undefined
>     b = (Base *)d;                    // Defined
>
> In other words, if reinterpret_cast is allowed to convert the pointer
> without changing its bits (and thus yielding an undefined result),
> why can't the C-style cast do this as well?

Because the use of reinterpret_cast<> in this context is covered only by
5.2.10 p7: "A pointer to an object can be explicitly converted to a
point to an object of a different type. 65) Except that converting an
rvalue of type "pointer to T1" to the type "pointer to T2" (where T1 and
T2 are object type and where the alignment requirements of T2 are no
stricter than those of T1) and back to it original type yields the
original pointer value, the result of such a pointer conversion is
unspecified."

Thus, the only thing you can safely do with the reinterpret_cast<>
pointer is to convert it back to the original type, and even that
depends upon the alignment restrictions. There's no guarantee what T2
object it points to, or even if it is a valid T2 pointer.

The C-style cast, on the other hand, is covered by 5.4 p7: "a pointer to
an object of derived class type ... may be explicitly converted to a
pointer or reference to an unambiguous base class type". There's no
spoiler warning like there is for reinterpret_cast<>, so I think we can
safely assume that the resulting pointer points at the base class
sub-object of the derived object that the original pointer pointed at (I
have to admit, however, that it doesn't explicitly say so).


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Darin Adler <darin@bentspoon.com>
Date: 2000/01/13
Raw View
In article <387CD191.2CB25424@tribble.com>, David R Tribble
<david@tribble.com> wrote:

> I don't mean to question your veracity, but why does a C-style cast
> return well-defined results, while a reinterpret_cast returns
> undefined results (in this situation)?
>
>     b = reinterpret_cast<Base *>(d);  // Undefined
>     b = (Base *)d;                    // Defined
>
> In other words, if reinterpret_cast is allowed to convert the pointer
> without changing its bits (and thus yielding an undefined result),
> why can't the C-style cast do this as well?

The standard specifically says that the C-style cast can do this
particular conversion (in a well-defined way, no because it works
without changing any bits). The standard does not say that the C-style
cast in this case converts the pointer without changing the bits; that's
what reinterpret_cast probably does, as you say, but the standard makes
a stronger guarantee for the C-style cast in this case.

As Steve Clamage mentioned earlier in this thread, this is covered in
the C++ Standard in paragraph 5.4/7. This is a special case for explicit
type conversion (what we're calling a C-style cast) when the only thing
that would prevent the static_cast from working is the fact that a base
class type is inaccessible.

    -- Darin

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: 2000/01/13
Raw View
David R Tribble <david@tribble.com> writes:

[...]

| In other words, if reinterpret_cast is allowed to convert the pointer
| without changing its bits (and thus yielding an undefined result),
| why can't the C-style cast do this as well?

I think the main difference lies in the fact that new-style casts
check for accessibility whereas C-style casts don't; in other words,
new-style casts and C-style casts have the same meaning modulo
accessibility.

--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Steve Clamage <stephen.clamage@sun.com>
Date: 2000/01/11
Raw View
Steve Clamage wrote:
>
> The February 2000 issue of C++ Report is scheduled to run a column
> by me discussing all the casts in detail.

Someone sent me by private email a query about C++ Report, but did
not provide a valid email address for a reply.

In case others are interested: I have seen C++ Report in large bookstores
like Crown or Barnes & Noble, and in technical bookstores. You can also
check the magazine's web site
 http://www.creport.com/

--
Steve Clamage, stephen.clamage@sun.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Steve Clamage <stephen.clamage@sun.com>
Date: 2000/01/11
Raw View
scott_seely@my-deja.com wrote:
>
> Your cast is legal here, but it is ill-advised.  Before I go into my
> rant, let me state that I recognize that you were only showing an
> example, not good programming practices.  That said, you still don't
> need a C-style cast--ever.

Sorry, that is false. The C-style cast allows well-defined conversions
that are not available using any other kind of cast. You can argue
that you should not want those conversions (and I might agree), but the
fact remains that they are valid, well-defined, and available only via
a C-style cast.

>  Phil forgot about reinterpret_cast<>.  Here
> is an extended example of his example.

Actually, it was my example.

>
> class base
> {
> public:
>     void doIt()
>     {
>         std::cout << "base::doit" << std::endl;
>     }
> };
> class derived : private base
> {
> public:
>     void doSomethingElse()
>     {
>         std::cout << "derived::doSomethingElse" << std::endl;
>     }
> };
>
> void f1()
> {
>     derived d;
>     //base* p1 = dynamic_cast<base*>(&d); // error, base is private
>     //base* p2 = static_cast<base*>(&d);  // error, base is private
>     base* p3 = (base*)(&d); // OK
>     base* p4 = reinterpret_cast<base*>(&d); //OK, and better because
>     // it explicitly states that you are bending the rules.

It is not better, because the results are unpredictable. Consider
multiple inheritance:

class b1 { ... }; // non-empty
class b2 { ... }; // non-empty
class derived : b1, b2 { ... };

derived d;
b1* p1 = reinterpret_cast<b1*>(&d);
b2* p2 = reinterpret_cast<b2*>(&d);

Since the b1 and b2 subobjects cannot have the same offset within a
derived object, it is not possible for both p1 and p2 to be valid.
At least one of them will not point to a subobject of the declared
type.  If instead you use a C-style cast, you will get the proper
pointer adjustment, and each of p1 and p2 will have the correct value.

You should NEVER use a reinterpret_cast for navigating within a class
hierarchy. If you get a valid result, it will be only by accident.
Even with single inheritance you are not assured by the language
definition to get a suitable result. With multiple inheritance,
you are likely to get an invalid result that compiles without
complaint but produces unpredictable results at run time.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Bill Wade" <bill.wade@stoner.com>
Date: 2000/01/12
Raw View
scott_seely@my-deja.com wrote in message <855qk9$fbo$1@nnrp1.deja.com>...
>    [ class derived: private base { ... }; ]
>    derived d;
>    base* p4 = reinterpret_cast<base*>(&d); // OK, and better because
>    // it explicitly states that you are bending the rules.
>    p4->doIt();

Compared to the old-style cast you aren't just bending the rules, you are
breaking them.  Dereferencing p4 results in undefined behavior.  The only
portable way to use p4 as a pointer value is to reinterpret_cast it back to
a derived*.

It is perfectly legal (and common) for an implementation to leave a
pointer's bits unchanged after a reinterpret cast.  If that is the case your
code only works when the base sub-object has the same address as the derived
object.  That is unlikely to be the case if there is more than one base
sub-object, and the standard doesn't require it even for simple inheritance.

For instance on my system (which I believe is conforming in this regard)
running the following program gives the "correct" answer (1,2) for the old
style cast and the "wrong" answer (1,1) for the new style cast.

// Compare results of reinterpret cast and old cast when private
// bases are involved.

#include <iostream>
using namespace std;

struct aa { int a; };
struct bb { int b; };

class derived: private aa, bb
{
public:
  derived(){ a = 1; b = 2; }
};

int main()
{
  derived d;
  aa* ap = (aa*)&d;
  bb* bp = (bb*)&d;
  cout << "Old " << ap->a << ' ' << bp->b << endl;

  ap = reinterpret_cast<aa*>(&d);
  bp = reinterpret_cast<bb*>(&d);

  // According to the standard dereferencing ap or bp is undefined,
  // but let's live dangerously.
  cout << "New " << ap->a << ' ' << bp->b << endl;

  return 0;
}



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <david@tribble.com>
Date: 2000/01/12
Raw View
[The example given was casting a pointer to a derived class to a
pointer to a base class, where the derived class privately inherits
the base class.

    class Base { ... };

    class Der: private Base { ... };

    void foo(Der *d)
    {
        Base *  b;

        b = dynamic_cast<Base *>(d);  // Illegal, Base inaccessible
        b = (Base *)d;                // Legal
    }
]

scott_seely@my-deja.com wrote:
>> Your cast is legal here, but it is ill-advised.  Before I go into my
>> rant, let me state that I recognize that you were only showing an
>> example, not good programming practices.  That said, you still don't
>> need a C-style cast--ever.

Steve Clamage wrote:
> Sorry, that is false. The C-style cast allows well-defined conversions
> that are not available using any other kind of cast. You can argue
> that you should not want those conversions (and I might agree), but
> the fact remains that they are valid, well-defined, and available
> only via a C-style cast.

I don't mean to question your veracity, but why does a C-style cast
return well-defined results, while a reinterpret_cast returns
undefined results (in this situation)?

    b = reinterpret_cast<Base *>(d);  // Undefined
    b = (Base *)d;                    // Defined

In other words, if reinterpret_cast is allowed to convert the pointer
without changing its bits (and thus yielding an undefined result),
why can't the C-style cast do this as well?

-- David R. Tribble, david@tribble.com, http://david.tribble.com --


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Beszedes Arpad <beszedes@cc.u-szeged.hu>
Date: 2000/01/06
Raw View
According to the standard, what is the difference between the C style
type cast and static_cast?

Arpad.

--
***********************************************
*  Arpad Beszedes (research engineer)         *
*                                             *
*  Research Group on Artificial Intelligence  *
*  Hungarian Academy of Sciences              *
*  Attila Jozsef University, Szeged, Hungary  *
*  e-mail: beszedes@cc.u-szeged.hu            *
*  tel.: (+36) 62/45-41-45                    *
***********************************************
* "To err is human, but to really mess things *
*          up you need a computer."           *
***********************************************
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "TiTi" <cenTipod@anTi.com>
Date: 2000/01/06
Raw View
C ( )-style can be a reinterpret_cast< > or a static_cast< >, depending on
the source and destination type.

TiTi



> According to the standard, what is the difference between the C style
> type cast and static_cast?
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: 2000/01/06
Raw View
Ron Natalie <ron@sensor.com> writes:

| Beszedes Arpad wrote:
| >
| > According to the standard, what is the difference between the C style
| > type cast and static_cast?
|
| A C style cast applies the first of the following C++ casts that is
| legal for the situation:
|  const_cast
|  static_cast followed by const_cast
|  reinterpret_cast
|  reintrepret_cast followed by const_cast

A C-style cast may be legal where no new-style cast can be applied.

--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Ron Natalie <ron@sensor.com>
Date: 2000/01/06
Raw View


Ron Natalie wrote:
>
> A C style cast applies the first of the following C++ casts that is
> legal for the situation:
>         const_cast
>         static_cast followed by const_cast
>         reinterpret_cast
>         reintrepret_cast followed by const_cast
>
It has come to my attention that I technically left one out.
The list should read:
        const_cast
        static_cast
        static_cast followed by const_cast
        reinterpret_cast
        reintrepret_cast followed by const_cast

(I left out the static_cast alone).



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Ron Natalie <ron@sensor.com>
Date: 2000/01/06
Raw View


Gabriel Dos Reis wrote:
>
> Ron Natalie <ron@sensor.com> writes:
>
> | Beszedes Arpad wrote:
> | >
> | > According to the standard, what is the difference between the C style
> | > type cast and static_cast?
> |
> | A C style cast applies the first of the following C++ casts that is
> | legal for the situation:
> |       const_cast
   static_cast
> |       static_cast followed by const_cast
> |       reinterpret_cast
> |       reintrepret_cast followed by const_cast
>
> A C-style cast may be legal where no new-style cast can be applied.
>

I disagree.  If none of the above cases is legitimately applied, the
program is ill-formed (i.e., warrants a diagnostic out of the compiler).



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Steve Clamage <stephen.clamage@sun.com>
Date: 2000/01/06
Raw View
Ron Natalie wrote:
>
> Gabriel Dos Reis wrote:
> >
> > Ron Natalie <ron@sensor.com> writes:
> >
> > | Beszedes Arpad wrote:
> > | >
> > | > According to the standard, what is the difference between the C style
> > | > type cast and static_cast?
> > |
> > | A C style cast applies the first of the following C++ casts that is
> > | legal for the situation:
> > |       const_cast
>           static_cast
> > |       static_cast followed by const_cast
> > |       reinterpret_cast
> > |       reintrepret_cast followed by const_cast
> >
> > A C-style cast may be legal where no new-style cast can be applied.
>
> I disagree.  If none of the above cases is legitimately applied, the
> program is ill-formed (i.e., warrants a diagnostic out of the compiler).

Refer to 5.4 paragraph 7, which lists additional conversions allowed
by a C-style cast that are not allowed by any of the other casts.

The February 2000 issue of C++ Report is scheduled to run a column
by me discussing all the casts in detail.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Ron Natalie <ron@sensor.com>
Date: 2000/01/07
Raw View

Beszedes Arpad wrote:
>
> According to the standard, what is the difference between the C style
> type cast and static_cast?

A C style cast applies the first of the following C++ casts that is
legal for the situation:
 const_cast
 static_cast followed by const_cast
 reinterpret_cast
 reintrepret_cast followed by const_cast

Example:
 const T* t;
 (T*) t;  // same as const_cast<T*>(t);

 struct B { };
 struct D : B { };
 B* b;
 (D*) b;  // same as static_cast<D*> t;

 const B* cb;
 (D*) cb; // same as const_cast<D*>(static_cast<const D*>(t))


 (D*) t  // same as reinterpret_cast<D*>(t);

(The last case is left as an excerise for the student).

-Ron

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Hyman Rosen <hymie@prolifics.com>
Date: 2000/01/07
Raw View
Ron Natalie <ron@sensor.com> writes:
> I disagree.  If none of the above cases is legitimately applied, the
> program is ill-formed (i.e., warrants a diagnostic out of the compiler).

I believe that there is no legal new-style cast which can cast
a pointer to a derived class into a pointer to a private base
class, but a C-style cast is permitted to do so.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Steve Clamage <stephen.clamage@sun.com>
Date: 2000/01/07
Raw View
Phil Edwards wrote:
>
> Gabriel Dos Reis  <dosreis@cmla.ens-cachan.fr> wrote:
> +
> + A C-style cast may be legal where no new-style cast can be applied.
>
> Really?  I can't think of an example... help?

Here's one:

class base { ... };
class derived : private base { ... };

void f1()
{
    derived d;
    base* p1 = dynamic_cast<base*>(&d); // error, base is private
    base* p2 = static_cast<base*>(&d);  // error, base is private
    base* p3 = (base*)(&d); // OK
}

A const_cast can't be used.

A reinterpet_cast in general will not produce the desired result.
The offset adjustment will probably not be applied, and in any
event the exact effect is not prescribed by the standard.

--
Steve Clamage, stephen.clamage@sun.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: scott_seely@my-deja.com
Date: 2000/01/07
Raw View
Your cast is legal here, but it is ill-advised.  Before I go into my
rant, let me state that I recognize that you were only showing an
example, not good programming practices.  That said, you still don't
need a C-style cast--ever.  Phil forgot about reinterpret_cast<>.  Here
is an extended example of his example.

class base
{
public:
    void doIt()
    {
        std::cout << "base::doit" << std::endl;
    }
};
class derived : private base
{
public:
    void doSomethingElse()
    {
        std::cout << "derived::doSomethingElse" << std::endl;
    }
};

void f1()
{
    derived d;
    //base* p1 = dynamic_cast<base*>(&d); // error, base is private
    //base* p2 = static_cast<base*>(&d);  // error, base is private
    base* p3 = (base*)(&d); // OK
    base* p4 = reinterpret_cast<base*>(&d); //OK, and better because
    // it explicitly states that you are bending the rules.
    p4->doIt();
}

int main(int argc, char* argv[])
{
 f1();
 return 0;
}

In article <38753445.68260778@sun.com>,
  Steve Clamage <stephen.clamage@sun.com> wrote:
> Phil Edwards wrote:
> >
> > Gabriel Dos Reis  <dosreis@cmla.ens-cachan.fr> wrote:
> > +
> > + A C-style cast may be legal where no new-style cast can be
applied.
> >
> > Really?  I can't think of an example... help?
>
> Here's one:
>
> class base { ... };
> class derived : private base { ... };
>
> void f1()
> {
>     derived d;
>     base* p1 = dynamic_cast<base*>(&d); // error, base is private
>     base* p2 = static_cast<base*>(&d);  // error, base is private
>     base* p3 = (base*)(&d); // OK
> }
>
> A const_cast can't be used.
>
> A reinterpet_cast in general will not produce the desired result.
> The offset adjustment will probably not be applied, and in any
> event the exact effect is not prescribed by the standard.
>
> --
> Steve Clamage, stephen.clamage@sun.com
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting
with ]
> [ your news-reader.  If that fails, use mailto:std-
c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---
               ]
> [ FAQ: http://reality.sgi.com/austern_mti/std-
c++/faq.html              ]
>
>


Sent via Deja.com http://www.deja.com/
Before you buy.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]