Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is using typeid on a forward declared type undefined behavior?

Am I reading the standard correctly in 5.2.8.3: ... If the type of the expression is a class type, the class shall be completely-defined. If the type is not "completely-defined" does that mean the following program is undefined?

foo.cpp:

struct foo
{
  virtual void a(){}
};

struct bar : foo
{
  virtual void a(){}
};

bar abar;

foo& get_some_foo()
{
  return abar;
}

main.cpp:

#include <iostream>
#include <typeinfo>

struct foo;

foo& get_some_foo();

int main()
{
  foo& a_ref_foo(get_some_foo());

  std::cout << "a_ref_foo typeid name: " << typeid(a_ref_foo).name() << std::endl;

  return 0;
}

MSVC10 outputs: `a_ref_foo typeid name: struct foo'

like image 302
Zac Avatar asked Jul 04 '12 00:07

Zac


People also ask

What is the purpose of the operator Typeid in C++?

typeid is an operator in C++. It is used where the dynamic type or runtime type information of an object is needed. It is included in the <typeinfo> library. Hence inorder to use typeid, this library should be included in the program.

Is forward declaration bad C++?

A forward declaration is not so much dangerous in itself, but it is a code smell. If you need a forward declaration, it means two classes are tightly coupled, which usually is bad. Thus it is an indication that your code may need refactoring.


2 Answers

When I compile your code with:

g++ foo.cpp main.cpp -o main

I get:

main.cpp: In function ‘int main()’:
main.cpp:12:52: error: invalid use of incomplete type ‘struct foo’
main.cpp:4:8: error: forward declaration of ‘struct foo’

That agrees with my interpretation of the standard, that you can't apply typeid to an incomplete type — and a_ref_foo is of an incomplete type, since the full definition of the type foo is not visible. main.cpp (with the lines I added) is ill-formed, and a diagnostic is required.

Update :

I've reproduced the issue with Visual Studio 2010 Express. Even with language extensions disabled, this trivial program:

#include <typeinfo>

struct foo;

int main()
{
  typeid (foo);
  return 0;
}

compiled with no diagnostic messages. With gcc 4.7, I get:

main.cpp: In function ‘int main()’:
main.cpp:7:14: error: invalid use of incomplete type ‘struct foo’
main.cpp:3:8: error: forward declaration of ‘struct foo’

The same rule:

If the type of the expression is a class type, the class shall be completely-defined.

appears in the 1998, 2003, and 2012 versions of the ISO C++ standard.

Looks like a bug in Visual Studio. (If somebody would like to report this to Microsoft, go ahead.)

like image 187
Keith Thompson Avatar answered Nov 15 '22 20:11

Keith Thompson


Yes, the program is ill-formed (rather than causing undefined behavior).

If you wonder why, then you should consider that typeid is a single operator, but it has completely different semantics for polymorphic types than for non-polymorphic types. In particular, if foo is polymorphic (has at least one virtual function, then typeid will yield a reference to the type_info object for the actual type (in this case bar) while if the type does not have any virtual function then it will return a reference to the type_info object for the static type of the expression (in this case foo).

For the compiler to generate the appropriate code, the compiler must know at the place where typeid is used which of the two cases applies. If the type is incomplete, that information is not present for the compiler.

like image 43
David Rodríguez - dribeas Avatar answered Nov 15 '22 21:11

David Rodríguez - dribeas