W dniu 4 października 2011 21:48 użytkownik Jon Cruz <jon@...1672....> napisał:
There are two main benefits:
- reduces compile time by avoiding pulling in additional headers.
Non-issue. The majority of compile time is spent on optimizations, not file I/O or parsing. If you want to improve your build times, disable optimization or use Clang.
- minimizes rebuild times when one header is changed.
On the other hand, if the forward declaration of some type changes (for example, it becomes a template or a typedef instead of an ordinary class), you have to change all files which use the type.
So we remove #including of detailed extra headers. That is good. However, if we replace that with "let's include this *different* file instead", then we lose much of the benefit. Though that one forward.h might compile a little faster, it still has to be checked and consulted. Also it introduces an artificial dependency that when touched will cascade out and cause more files to be compiled than should. (The main example we have in our source code of such cascading is verbs.h - touch that and the whole world rebuilds)
verbs.h is not a forward declaration header.
Take a look at the changes I was making. Among other things you should see that though there might be dozens of declarations in a forward.h, any given .h file only needs perhaps one or two of those.
So maybe you should start replacing <glib.h> in files which use only a few GLib functions with the prototypes of those functions?
Then over time the forward.h files tend to accumulate cruft. If the have outdated or sometimes wrong declarations, or unused ones, they just add to the potential for slowdown or error. On the other hand if forward declarations are in a file that needed them, one can very trivially search that one .h file to see if they are used. If not, they can be removed with no problem. Much easier to keep in sync and free of cruft. And safer to do so also (especially when one considers conditional or platform specific code). And safer code is good code.
This is actually an argument in favor of forward headers! You run at a much greater risk of having outdated forward declarations if you put them directly in the header using them. What's easier - changing a forward declaration in one place or changing it in 20 places?
So picture a specific method being added that takes a reference to some type. One approach is for the coder to add a forward declaration for that type in the .h file that he is also adding the method to. One file touched, and only consumers of that specific file get rebuilt.
The alternative is to place the type in a forward.h. So in that case the coder has to edit the .h to add a new method, also add a new #include line to that same .h and expand it's dependencies, and finally has to also edit the pertinent forward.h file to add a declaration for that type. At least two .h files get changed, but since one is a .h file that is pulled into many other .h files *and* .cpp files (though .cpp files should never use them, they often end up accidentally having them). So now many dozens of .cpp files get rebuilt in response to what should have been an isolated case.
Your example is bad. If you are adding a method that uses some type by reference, you almost never have to add this type to the forward header, because it's already there! Additionally, the forward declaration might be non-trivial (e.g. namespaced) or even an implementation detail (e.g. template types which are only supposed to be used as typedefed secializations, such as Geom::Rect).
This problem only applies if you are adding a new type to the library that has the forward header, which is a much less frequent occurrence.
Regards, Krzysztof