An idea for the recursive inclusion problem

J

Juha Nieminen

Multiple inclusion of the same header file can cause the compilation
to fail because of multiple definitions of the same type. That's why
it's standard practice to write all headers like this:

// SomeClass.hh
#ifndef SOME_CLASS_HH
#define SOME_CLASS_HH

class SomeClass
{
...
};

#endif

In complex projects recursive inclusion happens. It can be a rather
long chain of headers including other headers in a loop, and it may
be easy to miss.
The problem is that when this happens, the compiler errors are
usually very confusing. In the worst case (this has happened to me)
the compiler starts giving errors on places which have so far
compiled without problems and you haven't touched for weeks. It can
easily be really confusing why the compiler suddenly started to
complain about something you haven't even modified. Unless you have
experienced it before, it can be really hard to guess that the
problem is in a recursive inclusion which formed when you wrote
that one #include in a seemingly unrelated header. (Depending on
the compiler and the project settings it may be completely unexpected
what will "break" first because of that.)

I was thinking: In most cases when this problem has happened to me,
it was easy to fix by removing the #include and replacing it with a
pre-declaration of the class, as this usually has happened only when
I use references/pointers to that class instead of instances. Thus if
all headers were written like this:

// SomeClass.hh
class SomeClass;

#ifndef SOME_CLASS_HH
#define SOME_CLASS_HH

class SomeClass
{
...
};

#endif

then recursive inclusion would not be a problem. If you are only
using pointer/references, then everything will compile and work ok.
And even if you are using the class as a member variable and you
simply can't do that, you will most probably get a more meaningful
error message, like "error: field `x' has incomplete type" (now you
only have to understand that "incomplete type" refers to the type
having only been pre-declared).

Can anyone think of a drawback of doing this?
 
P

Puppet_Sock

Multiple inclusion of the same header file can cause the compilation
to fail because of multiple definitions of the same type. That's why
it's standard practice to write all headers like this:

// SomeClass.hh
#ifndef SOME_CLASS_HH
#define SOME_CLASS_HH

class SomeClass
{
...

};

#endif

In complex projects recursive inclusion happens. It can be a rather
long chain of headers including other headers in a loop, and it may
be easy to miss.
The problem is that when this happens, the compiler errors are
usually very confusing. In the worst case (this has happened to me)
the compiler starts giving errors on places which have so far
compiled without problems and you haven't touched for weeks. It can
easily be really confusing why the compiler suddenly started to
complain about something you haven't even modified. Unless you have
experienced it before, it can be really hard to guess that the
problem is in a recursive inclusion which formed when you wrote
that one #include in a seemingly unrelated header. (Depending on
the compiler and the project settings it may be completely unexpected
what will "break" first because of that.)

I was thinking: In most cases when this problem has happened to me,
it was easy to fix by removing the #include and replacing it with a
pre-declaration of the class, as this usually has happened only when
I use references/pointers to that class instead of instances. Thus if
all headers were written like this:

// SomeClass.hh
class SomeClass;

#ifndef SOME_CLASS_HH
#define SOME_CLASS_HH

class SomeClass
{
...

};

#endif

then recursive inclusion would not be a problem. If you are only
using pointer/references, then everything will compile and work ok.
And even if you are using the class as a member variable and you
simply can't do that, you will most probably get a more meaningful
error message, like "error: field `x' has incomplete type" (now you
only have to understand that "incomplete type" refers to the type
having only been pre-declared).

Can anyone think of a drawback of doing this?

Ok, I can't see that you gain anything from this.
If you have double include guards, you have them.
If you don't have them, then adding this forward
declaration does not seem to gain you anything.
Socks
 
J

James Kanze

Multiple inclusion of the same header file can cause the compilation
to fail because of multiple definitions of the same type. That's why
it's standard practice to write all headers like this:
// SomeClass.hh
#ifndef SOME_CLASS_HH
#define SOME_CLASS_HH

class SomeClass
{
...
};
#endif
In complex projects recursive inclusion happens. It can be a rather
long chain of headers including other headers in a loop, and it may
be easy to miss.
The problem is that when this happens, the compiler errors are
usually very confusing. In the worst case (this has happened to me)
the compiler starts giving errors on places which have so far
compiled without problems and you haven't touched for weeks. It can
easily be really confusing why the compiler suddenly started to
complain about something you haven't even modified. Unless you have
experienced it before, it can be really hard to guess that the
problem is in a recursive inclusion which formed when you wrote
that one #include in a seemingly unrelated header. (Depending on
the compiler and the project settings it may be completely unexpected
what will "break" first because of that.)
I was thinking: In most cases when this problem has happened to me,
it was easy to fix by removing the #include and replacing it with a
pre-declaration of the class, as this usually has happened only when
I use references/pointers to that class instead of instances. Thus if
all headers were written like this:
// SomeClass.hh
class SomeClass;
#ifndef SOME_CLASS_HH
#define SOME_CLASS_HH
class SomeClass
{
...
};
#endif
then recursive inclusion would not be a problem. If you are only
using pointer/references, then everything will compile and work ok.
And even if you are using the class as a member variable and you
simply can't do that, you will most probably get a more meaningful
error message, like "error: field `x' has incomplete type" (now you
only have to understand that "incomplete type" refers to the type
having only been pre-declared).
Can anyone think of a drawback of doing this?

Compile times will shoot up, since the typical optimization of
not re-opening a file protected by include guards won't work.

It masks, rather than corrects, a real problem.
 
J

Juha Nieminen

Puppet_Sock said:
Ok, I can't see that you gain anything from this.

If what you are using is only references/pointers to the class,
the program will compile ok regardless of the recursive inclusion.
 
J

Juha Nieminen

James said:
Compile times will shoot up, since the typical optimization of
not re-opening a file protected by include guards won't work.

You mean some compilers do that automatically? Which ones?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top