I'm now in the process of re-factoring c++ libraries I'm working on (mainly legacy), and I'm trying to minimize the include directives and recursive dependencies resulted from these inclusions.
Also, for making the forward declaration handling neat and easy, I maintain a fwd.h in each library, (like iosfwd in std), which make library's clients life easier
Is there a case when include should be preferred over forward declaration (**when both cases compiles) ?**
I am not interested in school book explanation when forward declaration is preferable. Maybe there is a point when forward declaration is pain in the neck.
What is the strategy in std, boost, or other well established libraries?
note: my compiler is intel icc 12 - supports only C++03 with very few C++11 features such as forward declaration of enums
ps: I have tackled with a similar discussion - and it appears that there is a case where forward declaration is worse than include - when deleting an incomplete an object of incomplete type:
[C++ Class forward declaration drawbacks?
#include is never better than forward declaration. Use #include when it is absolutely necessary.
And #include is only necessary when the full type information is needed like declaring class member or invoking member method of in the containing class header file. In following cases it is not required:
using pointer/reference as class member
In function signature (parameter or return type)
Only when the code won't compile! Always use and if possible refactor code to use forward declarations over #include's.
Related
The C++ standard does not allow code to forward declare classes in namespace std, even when they are not templates.
I see no good reason to do this, so I wonder what is the motivation?
It could be a huge compile time improvement. For example std::mutex is a simple class, but the <mutex> header drags in a ton of stuff (at least on my implementation).
If somebody wonders why I am making a distinction between templates and non-templates, then it is because template instantiations can differ significantly based on what template arguments are provided, so I guess that might be trickier to implement/support.
for example std::mutex is a simple class
How do you know? The standard describes it as a class, but nothing is stopping an implementer from doing
namespace std {
using mutex = _Internal_detail::_PthreadMutex;
}
Granted, I omitted some (likely very verbose and expert friendly) checks for when this alias should be set. But this is a valid implementation technique!
Now if you add your forward declaration, you will get an error since an alias and a class are different things. That makes such forward declarations inherently non-portable, and as such, they are deemed to produce undefined behavior.
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
Forward declarations can hide a dependency, allowing user code to skip necessary recompilation when headers change.
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.
Forward declaring symbols from namespace std:: yields undefined behavior.
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:
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*).
Forward declaring multiple symbols from a header can be more verbose than simply #includeing the header.
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?
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.
From Titus Winters' CppCon 2014 talk:
The big one that we've learned lately is: Forward declaring anything with a template in it is a really bad idea. This led to maintenance problems like you would not believe. Forward declaration may be okay, in some cases? My suspicion is the rule is actually going to change to: Library owners are encouraged to provide a header that specifically forward declares the things that they think are worth it (emphasis added), and you probably shouldn't forward declare yourself, and nobody should ever forward declare a templated type. We'll see. We're still working out the [inaudible] details from what we've learned.
So maybe issues with trying to directly forward declare templated types might be one of their motives for discouraging forward declaration wholesale...?
Also, providing "a header that specifically forward declares the things that they think are worth it" sounds similar to the way <iosfwd> is used, as described here (Solution 2.2), here, and here.
EDIT:
To be clear, I wasn't saying I agree or disagree with Google's discouragement of forward declaration. I was just trying to understand their rationale, and made an aside/observation about <iosfwd>.
Personally, I use forward declarations whenever I can, following the guideline stated later in that same GOTW linked above (Solution 3):
Guideline: Never #include a header when a forward declaration will suffice.
but Winters' reasoning seems to have some merit as well. I've worked on code where I forward declared templated types from a third party library, and the syntax does get messy (I haven't yet run into the maintenance problems Winters alluded to). OTOH, I'm not so sure about discouraging all forward declarations as stated in the Google C++ Style Guide, but I guess that's what works for Google?
Disclaimer: I'm no expert, still learning.
I'm new in c++ world, and learned that it is a good practice to make forward declarations. But is it always good?
I'm looking for guidelines for when it is a good practice to make a forward declaration and when it is not good, but I really couldn't find any. There are any objective case for when it should be used or not, or it is entirely up to the developer?
There can be cases where you actually start complicating your code base with otherwise unnecessary applications of the PIMPL idiom (which involves forward declarations) to reduce compilation time when in fact you do not have any compilation speed problems in the first place, at least with that particular class or header file.
This can then be considered a case of premature optimisation and a misuse of forward declarations.
As mentioned by juanchopanza, in general you can use forward declarations when you don't need a full class definition - basically when you don't need to know the size or members of the class in question. It allows you to remove compile-time dependencies, which can simplify and speed-up compilations.
For example, if you only use pointers to a class, then you don't need to know any more about it. However, if you call a method of that class, or store an actual instance of it, then you need to know the full details of the class.
class A; // forward declaration
class B {
...
void func1(A*);
}
class C {
...
A m_inst;
}
In the above, C will not compile, as it needs to know the size of A at the point of declaration. However, func1 is fine, as it only uses a pointer to A, so doesn't need to know size or implementation.
Herb Sutter has a bit of information along with explanations, although be warned that some of it is a little advanced if you're a beginner.
The standard library includes an <iosfwd> header, that (forward) declares all streams including any typedefs and defines the char_traits template, including the specializations.
Sadly, there is no such <stlfwd> header that (forward) declares all the common STL datatypes and functions like vector, map, less, sort, etc. Even more sadly, user code is not allowed to add such declarations / typedefs to the std namespace, as per
§17.4.3.1 [lib.reserved.names] p1:
It is undefined for a C + + program to add declarations or definitions to namespace std or namespaces within namespace std unless otherwise specified. A program may add template specializations for any standard library template to namespace std.
Yep, that covers the case of (forward) declarations, even if the types already exist in the standard library. Of course, most (all?) compilers will behave perfectly normal even if one adds such declarations, but strictly and language lawyer speaking, it is undefined behaviour. I find this especially tedious for typedefing standard containers, like:
// how to forward declare map and string?
typedef std::map<std::string, std::string> Attributes;
Now, can this be considered a defect?
I mean both the non-existence of a <stlfwd> header (or better, <stdfwd>, covering <iosfwd> too) and the ban on declarations already existing in the standard library.
Also, according to this question, if one (forward) declares the standard container, algorithms and functors / functionals exactly as demanded by the standard, the code should be perfectly valid (if it weren't for the ban of user-made declarations in the std namespace), because implementations aren't allowed to add any hidden/defaulted template parameters.
I am asking this because I'm thinking of eventually submitting a defect report regarding this.
What would be the purpose of forward declaring say less or sort or really any other algorithm? If you're passing a general purpose algorithm around it will almost certainly be as a template type and not need a forward declaration at all.
That leaves us with the container types. There are definitely cases where forward declarations of them would be useful but I suspect that it was simply decided that as each container definition is relatively simple (compared to iostreams) it would be preferable to just use the full include rather than a <containerfwd> include for example.
An excerpt from "Exceptional C++":
"In the old days, you could just replace "#include " with "class ostream;" in this situation, because ostream used to be a class and it wasn't in namespace std. Alas, no more. Writing "class ostream;" is illegal for two reasons:
ostream is now in namespace std, and programmers aren't allowed to declare anything that lives in namespace std.
ostream is now a typedef of a template; specifically, it's typedef'd as basic_ostream. Not only would the basic_ostream template be messy to forward-declare in any case, but you couldn't reliably forward-declare it at all, because library implementations are allowed to do things like add their own extra template parameters (beyond those required by the standard), which, of course, your code wouldn't know about—one of the primary reasons for the rule that programmers aren't allowed to write their own declarations for things in namespace std."
My question:
I don't understand the part marked in bolds.
Thanks,
The part in bolds just says you can't forward declare ostream like this:
class ostream;
because ostream now is a typedef, and the details of declaration may or may not vary on different implementations.
because programmers are not allowed to declare anything in namespace std (though it will work on the majority of compilers).
If you want a forward declaration of ostream, include <iosfwd> instead. (Or look inside what it looks like for your implementation).
You can, if you are OK with the fact, that it will only work for a specific version of a specific compiler. It will be ugly, but you can do it (you can pretty much copy the content of the header into your code, and it will still work).
The reason why you shouldn't is exactly why it is in the header. You want to use some external interface and don't want to care about the compiler internals. The compiler guarantees you the external interface. As for the implementation, that's the compilers choice.