Woofas Woofas - 8 months ago 87
C++ Question

Why does Google Style Guide discourage forward declaration?

Not to say that the Google Style Guide is the holy bible but as a newbie programmer, it seems like a good reference.

The Google Style Guide lists the following disadvantages of forward declaration

  1. Forward declarations can hide a dependency, allowing user code to skip necessary recompilation when headers change.

  2. A forward declaration may be broken by subsequent changes to the library. Forward declarations of functions and templates can prevent the header owners from making otherwise-compatible changes to their APIs, such as widening a parameter type, adding a template parameter with a default value, or migrating to a new namespace.

  3. Forward declaring symbols from namespace std:: yields undefined behavior.

  4. It can be difficult to determine whether a forward declaration or a full #include is needed. Replacing an #include with a forward declaration can silently change the meaning of code:


// b.h:
struct B {};
struct D : B {};

// good_user.cc:
#include "b.h"
void f(B*);
void f(void*);
void test(D* x) { f(x); } // calls f(B*)

If the #include was replaced with forward decls for B and D, test() would call f(void*).

  1. Forward declaring multiple symbols from a header can be more verbose than simply #includeing the header.

  2. Structuring code to enable forward declarations (e.g. using pointer members instead of object members) can make the code slower and more complex.

However, some search on SO seemed to suggest that forward declaration is universally a better solution.

So given these seemingly non-trivial disadvantages, can someone explain this discrepancy?

And when is it safe to ignore some or all of these disadvantages?

Answer Source

some search on SO seemed to suggest that forward declaration is universally a better solution.

I don't think that's what SO says. The text you quote is comparing a "guerilla" forward declaration against including the proper include file. I don't think you'll find a lot of support on SO for the approach Google is criticising here. That bad approach is, "no, don't #include include files, just write declarations for the few functions and types you want to use".

The proper include file will still contain forward declarations of its own, and a search on SO will suggest that this is the right thing to do, so I see where you got the idea that SO is in favour of declarations. But Google isn't saying that a library's own include file shouldn't contain forward declarations, it's saying that you shouldn't go rogue and write your own forward declaration for each function or type you want to use.

If you #include the right include file, and your build chain works, then the dependency isn't hidden and the rest of the problems mostly don't apply, despite the fact that the include file contains declarations. There are still some difficulties, but that's not what Google is talking about here.

Looking in particular at forward declarations of types as compared with class definitions for them, (4) gives an example of that going wrong (since a forward declaration of D cannot express that it's derived from B, for that you need the class definition). There's also a technique called "Pimpl" that does make careful use of a forward type declaration for a particular purpose. So again you'll see some support on SO for that, but this isn't the same as supporting the idea that everyone should in general run around forward-declaring classes instead of #includeing their header files.