471,310 Members | 1,102 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,310 software developers and data experts.

An idea for the recursive inclusion problem

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?
Jul 5 '07 #1
6 3734
On Jul 5, 1:30 pm, Juha Nieminen <nos...@thanks.invalidwrote:
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

Jul 5 '07 #2
On Jul 5, 7:30 pm, Juha Nieminen <nos...@thanks.invalidwrote:
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.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jul 6 '07 #3
Puppet_Sock wrote:
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.
Jul 6 '07 #4
James Kanze wrote:
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?
Jul 6 '07 #5
On Fri, 06 Jul 2007 12:48:56 +0300, Juha Nieminen wrote:
James Kanze wrote:
>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?
gcc definitely does it.

--
Markus Schoder
Jul 6 '07 #6
On Jul 7, 1:20 am, Markus Schoder <a3vr6dsg-use...@yahoo.dewrote:
On Fri, 06 Jul 2007 12:48:56 +0300, Juha Nieminen wrote:
James Kanze wrote:
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?
gcc definitely does it.
gcc has been doing it for years. If others haven't followed
suite, they're asleep on the job. It's really not difficult.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jul 7 '07 #7

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

11 posts views Thread by Alexander Stippler | last post: by
4 posts views Thread by Kristian | last post: by
2 posts views Thread by krema2ren | last post: by
2 posts views Thread by Pindare | last post: by
1 post views Thread by Alkimake | last post: by
reply views Thread by rosydwin | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.