12

I'm fairly new to C++, but my understanding is that a #include statement will essentially just dump the contents of the #included file into the location of that statement. This means that if I have a number of '#include' and 'using' statements in my header file, my implementation file can just #include the header file, and the compiler won't mind if I don't repeat the other statements.

What about people though?

My main concern is that if I don't repeat the '#include', 'using', and also 'typedef' (now that I think of it) statements, it takes that information away from the file in which it's used, which could lead to confusion.

I am just working on small projects at the moment where it won't really cause any issues, but I can imagine that in larger projects with more people working on them it could become a significant issue.

An example follows:

UPDATE: my function prototypes for 'Unit' have string, ostream and StringSet among their return types and parameters - I am not including anything in my header file that is used only in the implementation file.

//Unit.h

#include <string>
#include <ostream>
#include "StringSet.h"

using std::string;
using std::ostream;

class Unit {

public:
    //public members with string, ostream and StringSet
    //in their return values/parameter lists
private:
    //private members
    //unrelated side-question: should private members
    //even be included in the header file?
} ;


//Unit.cpp

#include "Unit.h"

//The following are all redundant from a compiler perspective:
#include <string>
#include <ostream>
#include "StringSet.h"

using std::string;
using std::ostream;

//implementation goes here
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
David Mason
  • 2,917
  • 4
  • 30
  • 45
  • An unrelated question that I didn't want to clutter the main question with is, since everyone seems to say that global 'using' statements are a bad idea, how can I have just a class 'using std::string' or something? Moving that statement into the class declaration causes a compiler error because it doesn't like namespaces in a 'using' statement in that location. – David Mason Apr 26 '10 at 23:39
  • 2
    What's wrong with explicitly saying `std::string`? – Travis Gockel Apr 26 '10 at 23:42
  • nothing much until it starts causing lines to break when they otherwise wouldn't, which reduces readability. Let's move away from std:: for a while though and say I wanted to make use of theLongestNamespeceNameInTheKnownUniverse::string - just to avoid the common 'you should always just type std::string' mantra (since I've heard it plenty of times already, and although a valid point it doesn't really help with the question at hand). – David Mason Apr 26 '10 at 23:53
  • 1
    I think the C++ way is not to use long namespace names for this reason :) I just use fully qualified names in the headers, and use `using` directives in the cpp files, I haven't found a better way. I keep most of the function definitions in the cpp files and that helps with the amount of fully qualified names and the number of includes in the headers. – Alex Korban Apr 27 '10 at 00:06

5 Answers5

11

A using-directive (using namespace std;) should not reside in a header unless it is contained within a function. It is bad practice. It is unlikely that every user of your header wants unqualified lookup for everything in a given namespace; the inclusion of unrelated headers can lead to unexpected ambiguity and compilation failures. Personally, I avoid the using-directive inside of functions for the same reasoning, but this is generally considered less harmful.

A type alias (either through typedef std::string string; or using string = std::string;) should be used carefully. Type definitions have meaning, so you should never redeclare it. For example, this is an error:

typedef int   myint;
typedef float myint;

because of conflicting types.

A using-declaration (using std::string; or using std::memcpy;) makes a symbol accessible for unqualified name lookup. It is extremely useful when getting for argument-dependent lookup correct, which usually doesn't matter unless you're writing a library. The advice is different depending on if you are bringing in a type or a function. Think of using-declarations with types in the same manner as a type alias: It does not make sense to have multiple definitions under the same name. With functions, all you are really doing is extending overload resolution to include a few more things (although it is usually not necessary).

// Finding multiple operator<< functions makes sense
using std::operator<<;
using mylib::operator<<;

// Finding multiple string classes does not make sense
using std::string;
using mylib::string;

For repeating #include, you should consider if you actually need to include the file in the header in the first place. Perhaps a forward declaration fits your needs.

Travis Gockel
  • 26,877
  • 14
  • 89
  • 116
  • I have updated the question to clarify: I avoid having any #includes in my header file unless I actually need them in the header file. I'm not sure if that forward declaration example applies if I'm making use of std::string or another class that I'm not defining - can you clarify how this would work if so? – David Mason Apr 26 '10 at 23:58
  • The problem with `std::string` is that it is really just `typedef basic_string string` ... the standard states: `It is undefined for a C++ program to add declarations or definitions to namespace std or namespaces within namespace std unless otherwise specified.` So...you can't forward-declare it. As far as the `really_long_namespace_name` question, this is where people use member types. `std::allocator` is a good example of this: http://www.cplusplus.com/reference/std/memory/allocator/ – Travis Gockel Apr 29 '10 at 07:12
  • In C++11 `using` can also be used for type alias declarations, which according to the standard is equivalent to a typedef. And since typedef are ok in headers the sentance _"You should never have a using statement in a header unless it it contained within a function."_ does not sound true anymore. – Zitrax Feb 16 '17 at 10:28
  • @Zitrax: Agreed. I think the C++11 (and beyond) advice would be more specific: "You should never have a `using namespace` directive..." After reading my advise again, it seems a bit stupid/misguided. Why did I think that a using declaration is any different than a `typedef`? – Travis Gockel Feb 16 '17 at 20:35
  • @Zitrax: Halfway through editing, I realized most of this is still applicable to pre-C++11, so I rewrote it to work for everyone. – Travis Gockel Feb 16 '17 at 21:26
6
  • Only include in a header/source what you really need (if forward declarations are available, and enough, then forward declare instead of including)
  • Don't use using statement in headers (unless inside function scopes)... Adding using in the header will pollute the namespaces of all the sources including the header.
  • You should make sure each file (header of source) includes everything it needs, and nothing more.

You don't need to care if some includes are redundant. Header guards and precompiler optimizations are there to handle that for you.

You should be able to manipulate each file in isolation.

For example, let's say you use the std::string in the header and in the source, but, as an "optimization", you only included the string in the header... If you discover later you don't need anymore the string in the header, and want to remove it (code cleaning, and all...), you will have to modify the source to include the string. Now, let's imagine you have TEN sources including the header...

Now, of course, you can have exceptions to this rule (for example, precompiled headers, or even headers woe sole aim is to do multiple includes as a courtesy), but by default, you should have self-sufficient header and source files (i.e. files that include anything they use, no more no less).

paercebal
  • 81,378
  • 38
  • 130
  • 159
0

Keep the header files to a minimum. This means as little include's as feasible. the .cpp file will usually include the corresponding header as well as any other headers necessary for implementation.

Nick
  • 109
  • 5
0

Like Travis said, you shouldn't have using statements in a header file because that means they will be included in all the translation units that include that header file, which can cause confusing issues.

If I only require the functionality from a header file in a cpp file, I only include it in that cpp file. It's good practice for larger projects because it means less work for the compiler. Also, wherever possible, I use forward declarations in the headers instead of includes (and again, include the headers in the cpp file).

Alex Korban
  • 14,916
  • 5
  • 44
  • 55
0

It's considered bad form to have a using statement in a header file at all, unless you are intentionally duplicating a symbol into a different namespace. It's ok to use in a cpp file.

Each typedef should exist only once in your codebase. That should be in a header file if it needs to be used in multiple cpp/h files. Duplicating them will cause you much grief.

A header file should have all the #include statements that it needs, and no others. If only pointers to a class are mentioned then use a forward declaration rather than including the header. Any other includes that are required only inside the cpp file should go there. Repeating the includes from the header is ok, but not required. It's just a style choice.

Alan
  • 4,897
  • 2
  • 24
  • 17