Topic: Safety of functional-style casts
Author: ademkin@earthlink.net (Andrew Demkin)
Date: Thu, 20 Dec 2001 00:06:25 GMT Raw View
Greetings,
Sections 5.2.3 [expr.type.conv] and 5.4 [expr.cast] of the standard suggest
that old-style and functional-style casts should be interpreted, in order,
as one of the following conversions:
- a static_cast (5.2.9),
- a static_cast followed by a const_cast,
- a reinterpret_cast (5.2.10), or
- a reinterpret_cast followed by a const_cast
If more than one conversion applies, the interpretation that appears first
in this list is the one that's chosen, even if it's ill-formed.
However, Section 5.4.9 goes on to say that for pointers to incomplete class
types, even if there is an inheritance relationship between the source and
destination classes, whether static_cast or reinterpret_cast is used is
unspecified.
Now, given the following:
struct A{};
struct B{};
typedef B* BPtr;
A a;
BPtr p1 = (BPtr) &a;
BPtr p2 = BPtr(&a);
BPtr p3 = static_cast<BPtr>(&a);
...I'd expect the final three statements to generate a compiler error
because struct B is not derived from struct A. In the two compilers I've
tested, only the explicit static_cast expression results in any diagnostic.
The way I read the standard, a compiler should only have latitude to use
reinterpret_cast if either struct A and/or struct B is an incomplete type.
I'm wondering whether I'm misinterpreting the standard or whether these
compilers are non-conforming.
For compatibility reasons with C, I can understand the desire to interpret
an old-style cast as a reinterpret_cast. But, if the compiler is free to
use reinterpret_cast for functional-style casts as well, then the
definitions of bind1st<> and bind2nd<> (20.3.6.2/4) are possibly unsafe for
pointer argument types.
For example, the compilers I've tested fail to detect the type error below
in the 2nd call to for_each():
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
struct A{};
struct B{};
struct Func : binary_function<const A*, int, void>
{
void operator()(const A*, int) const;
};
void UnsafeBind()
{
A a;
B b;
Func f;
vector<int> v;
for_each(v.begin(), v.end(), bind1st(f, &a));
for_each(v.begin(), v.end(), bind1st(f, &b)); // woops!
}
The intent of the language must be to catch sort of error, no?
Thanks,
Andrew.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Martin von Loewis <loewis@informatik.hu-berlin.de>
Date: Thu, 20 Dec 2001 18:46:41 GMT Raw View
ademkin@earthlink.net (Andrew Demkin) writes:
> The way I read the standard, a compiler should only have latitude to use
> reinterpret_cast if either struct A and/or struct B is an incomplete type.
> I'm wondering whether I'm misinterpreting the standard or whether these
> compilers are non-conforming.
You are misinterpreting it. In your example, the explicit type
notation "cannot be interpreted" as a static_cast, thus it is a
reinterpret_cast.
Presumably, you where thinking that
BPtr p1 = (BPtr) &a;
"can be interpreted" as
BPtr p1 = static_cast<BPtr>(&a);
but is ill-formed, thus the explicit type conversion is ill-formed.
I'd admit that this looks like a defect, for not elaborating "can be
interpreted": it apparently means something else than "is
well-formed". The common interpretation is that the only case that is
ruled out (i.e. where it can be interpreted as a static case that is
ill-formed) is the case of ambiguity, as explained in the next
sentence.
> for_each(v.begin(), v.end(), bind1st(f, &a));
> for_each(v.begin(), v.end(), bind1st(f, &b)); // woops!
> }
>
> The intent of the language must be to catch sort of error, no?
That sounds like a defect in bind1st to me, for not mandating a
static_cast of the value argument.
Regards,
Martin
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: ademkin@earthlink.net (Andrew Demkin)
Date: Fri, 21 Dec 2001 13:17:25 CST Raw View
In article <j4itb2brsq.fsf@informatik.hu-berlin.de>, Martin von Loewis
<loewis@informatik.hu-berlin.de> wrote:
> You are misinterpreting it. In your example, the explicit type
> notation "cannot be interpreted" as a static_cast, thus it is a
> reinterpret_cast.
Martin, thanks for the clarification.
> I'd admit that this looks like a defect, for not elaborating "can be
> interpreted": it apparently means something else than "is
> well-formed". The common interpretation is that the only case that is
> ruled out (i.e. where it can be interpreted as a static case that is
> ill-formed) is the case of ambiguity, as explained in the next
> sentence.
>
> > for_each(v.begin(), v.end(), bind1st(f, &a));
> > for_each(v.begin(), v.end(), bind1st(f, &b)); // woops!
> > }
> >
> > The intent of the language must be to catch sort of error, no?
>
> That sounds like a defect in bind1st to me, for not mandating a
> static_cast of the value argument.
I too think this is a defect. What I'm still trying to decipher, however,
is whether it's best to report something against bind1st/2nd, or against
explicit type conversion (5.2.3).
Disclaimer: I don't have a copy of the ARM close-by, and I've only had a
brief look at C99, but what escapes me is why a functional-style
conversion like "BPtr(&a)" allows a reinterpret_cast which requires no
diagnostic. Since the same syntax "T(x)" is used for object construction,
which normally involves static type-checking, I'm trying to reconcile this
inconsistency.
My recollection of C is that it does not support functional-style
conversions -- only casts of the form "(T) x" -- so I would not expect
legacy C to influence the current semantics. Of course, if this is a
compatibility issue, I'll accept it as unfortunate and note a defect in
bind1st/2nd.
-- Andrew.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]