Topic: typeid(*(int*)0)


Author: Martin von Loewis <loewis@informatik.hu-berlin.de>
Date: 1998/11/08
Raw View
What is the semantics of evaluating 'typeid(*(int*)0)'?

It seems there are three options

1. this is a null-pointer dereference, and thus undefined behaviour.
2. this is an expression of the structure *(T*)0, and should therefore
   throw std::bad_typeid.
3. the expression has a static type int, and should therefore return
   a reference to typeid(int).

Which of these is expected in a conforming implementation?

TIA,
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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1998/11/09
Raw View
Martin von Loewis wrote:
 >
 > What is the semantics of evaluating 'typeid(*(int*)0)'?
 >
 > It seems there are three options
 >
 > 1. this is a null-pointer dereference, and thus undefined behaviour.
 > 2. this is an expression of the structure *(T*)0, and should therefore
 >    throw std::bad_typeid.
 > 3. the expression has a static type int, and should therefore return
 >    a reference to typeid(int).
 >
 > Which of these is expected in a conforming implementation?

By my reading of section 5.2.8, it should be 2.


[ 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: "Ross Smith" <ross.s@ihug.co.nz>
Date: 1998/11/09
Raw View
Martin von Loewis wrote in message ...
>What is the semantics of evaluating 'typeid(*(int*)0)'?
>
>It seems there are three options
>
>1. this is a null-pointer dereference, and thus undefined behaviour.
>2. this is an expression of the structure *(T*)0, and should therefore
>   throw std::bad_typeid.
>3. the expression has a static type int, and should therefore return
>   a reference to typeid(int).
>
>Which of these is expected in a conforming implementation?

The standard seems to be a bit unclear on this, but I'd go for 3. The
situation seems to fit paragraph 3 of [expr.typeid], which says that
the expression is not evaluated and presumably therefore can include
a dereferenced null pointer without hardship. Quoting CD2 (yes, I know
-- #include <std_moderator_moan_about_un_american_activities>):

 5.2.8  Type identification                               [expr.typeid]

 2 When  typeid  is applied to an lvalue expression whose type is a poly-
   morphic class type (_class.virtual_), the result refers to a type_info
   object   representing   the   type   of   the   most   derived  object
   (_intro.object_) (that is, the  dynamic  type)  to  which  the  lvalue
   refers.   If the lvalue expression is obtained by applying the unary *
   operator  to  a  pointer8)  and  the  pointer  is a null pointer value
   (_conv.ptr_), the typeid expression throws  the  bad_typeid  exception
   (_lib.bad.typeid_).

 3 When  typeid  is  applied  to  an expression other than an lvalue of a
   polymorphic class type, the result refers to a type_info object repre-
   senting   the   static   type  of  the  expression.   Lvalue-to-rvalue
   (_conv.lval_),  array-to-pointer  (_conv.array_),   and   function-to-
   pointer  (_conv.func_)  conversions are not applied to the expression.
   If the type of the expression is a class type, the class shall be com-
   pletely-defined.  The expression is not evaluated.

   8) If p is an expression of pointer type, then *p, (*p), *(p), ((*p)),
   *((p)), and so on all meet this requirement.

--
Ross Smith ................................... mailto:ross.s@ihug.co.nz
.............. The Internet Group, Auckland, New Zealand ..............
                               * * * * *
      "Screw up your courage. You've screwed up everything else."




[ 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: "Christopher M. Gurnee" <gurnec_at_mediaone_dot_net@127.0.0.1>
Date: 1998/11/09
Raw View
Martin von Loewis wrote in message ...
>What is the semantics of evaluating 'typeid(*(int*)0)'?
>
>It seems there are three options
>
>1. this is a null-pointer dereference, and thus undefined behaviour.
>2. this is an expression of the structure *(T*)0, and should therefore
>   throw std::bad_typeid.
>3. the expression has a static type int, and should therefore return
>   a reference to typeid(int).
>
>Which of these is expected in a conforming implementation?
>

typeid considers the static type of the expression without evaluating
it; from above, number 3 is expected.  An exception to this rule occurs
when the expression is an lvalue of polymorphic class type; in this
case, typeid considers the dynamic type of the expression, throwing
bad_typeid if and only if the expression consists of a dereferenced
pointer, and the pointer is a null pointer value.  Unfortunately, the
standard (quoted at the bottom) is a bit unclear in one point.  When
applied to an lvalue of polymorphic class type, is the expression
evaluated?  More specifically, given

class Foo {virtual ~Foo();};

Foo& getFoo();

void main() { cout << typeid(getFoo()).name(); }

is bar called?  The expression bar() is an lvalue of type Foo; in order
to determine its dynamic type, it must be evaluated.  I don't know if
this is the intent, but that's the way I interpret it.  This seems to
break the rule of least surprise, evaluating the expression only under
certain circumstances.

Perhaps it's just assumed that the user is knowledgable enough to know
when the expression is evaluated and when it isn't; after all, typeid
does parallel dynamic_cast in some manner.  However, if you try to take
the typeid of a non-polymorphic class type lvalue, you don't get an
error (as you shouldn't); with dynamic_cast, you always get either an
error or what's expected.

Also, a completely unrelated and pretty pointless question:  Is typeid
considered an operator?  sizeof is stated as one in the standard, is
typeid?

-Chris Gurnee

5.2.8:

2 When  typeid  is applied to an lvalue expression whose type is a poly-
  morphic class type (_class.virtual_), the result refers to a type_info
  object   representing   the   type   of   the   most   derived  object
  (_intro.object_) (that is, the  dynamic  type)  to  which  the  lvalue
  refers.   If the lvalue expression is obtained by applying the unary *
  operator  to  a  pointer8)  and  the  pointer  is a null pointer value
  (_conv.ptr_), the typeid expression throws  the  bad_typeid  exception
  (_lib.bad.typeid_).

3 When  typeid  is  applied  to  an expression other than an lvalue of a
  polymorphic class type, the result refers to a type_info object repre-
  senting   the   static   type  of  the  expression.   Lvalue-to-rvalue
  (_conv.lval_),  array-to-pointer  (_conv.array_),   and   function-to-
  pointer  (_conv.func_)  conversions are not applied to the expression.
  If the type of the expression is a class type, the class shall be com-
  pletely-defined.  The expression is not evaluated.





[ 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: Miniussi <miniussi@ilog.fr>
Date: 1998/11/09
Raw View
Martin von Loewis wrote:

> What is the semantics of evaluating 'typeid(*(int*)0)'?

> It seems there are three options

> 1. this is a null-pointer dereference, and thus undefined behaviour.

> 2. this is an expression of the structure *(T*)0, and should therefore
>    throw std::bad_typeid.

> 3. the expression has a static type int, and should therefore return
>    a reference to typeid(int).

> Which of these is expected in a conforming implementation?

I would say 3:

1) no, 5.2.8(3) says that the expression is not evaluated for a non
plymorphic type.

2) *(T*)0 is not of polymorphic type, so 5.2.8(2) doe not apply


Alain


[ 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: "Alfred Kellner" <alfkellner@magnet.at>
Date: 1998/11/10
Raw View
Martin von Loewis <loewis@informatik.hu-berlin.de>
> What is the semantics of evaluating 'typeid(*(int*)0)'?
>
> It seems there are three options
>
> 1. this is a null-pointer dereference, and thus undefined behaviour.
> 2. this is an expression of the structure *(T*)0, and should therefore
>    throw std::bad_typeid.
> 3. the expression has a static type int, and should therefore return
>    a reference to typeid(int).
>
> Which of these is expected in a conforming implementation?
>
My guess is .... 3.

<quote ISO 14882>
5.2.8 Type identification [expr.typeid]
 (3) When typeid is applied to an expression
 other than an lvalue of a polymorphic class type,
 the result refers to a type_info object
 representing the static type of the expression.
 ......
 The expression is not evaluated.
</quote>
Any doubts ?
 --ALfred


[ 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: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1998/11/10
Raw View
On 08 Nov 98 22:21:24 GMT, Martin von Loewis

>What is the semantics of evaluating 'typeid(*(int*)0)'?





Author: Miniussi <miniussi@ilog.fr>
Date: 1998/11/10
Raw View
"Christopher M. Gurnee" wrote:
>
> [..]  When
> applied to an lvalue of polymorphic class type, is the expression
> evaluated?  More specifically, given

Seems to be the only ways to check that :
>   [...]   If the lvalue expression is obtained by applying the unary *
>   operator  to  a  pointer8)  and  the  pointer  is a null pointer value
>   (_conv.ptr_), the typeid expression throws  the  bad_typeid  exception
>   (_lib.bad.typeid_).

Alain
---
[ 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: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/11/10
Raw View
Christopher M. Gurnee wrote:
>
> More specifically, given
>
> class Foo {virtual ~Foo();};
>
> Foo& getFoo();
>
> void main() { cout << typeid(getFoo()).name(); }
>
> is bar called?  The expression bar() is an lvalue of type Foo; in
> order
> to determine its dynamic type, it must be evaluated.  I don't know if
> this is the intent, but that's the way I interpret it.  This seems to
> break the rule of least surprise, evaluating the expression only under
> certain circumstances.

(I assume you half changed bar to getFoo.) Yes, it must be evaluated.
Since the compiler knows the type is polymorphic, it _must_ look at the
type of an actual object. (In most implementations, this means following
the vtbl pointer in the object.)

> Also, a completely unrelated and pretty pointless question:  Is typeid
> considered an operator?  sizeof is stated as one in the standard, is
> typeid?

"typeid" isn't an operator. "sizeof" is one because it doesn't
necessarily need parentheses around its operand. However, although both
sizeof and typeid can be applied to a type or to an object, they differ
in one important respect: sizeof(x), where x is a polymorphic type, does
not evaluate its argument in order to find out the true run-time size.
This allows sizeof(x) always to be a compile-time constant. In other
words, it is expected that typeid may call an actual function at
run-time, so it seems more appropriate to require functional notation
for it.

--

Ciao,
Paul
---
[ 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              ]