Discussion
Team LiB
Previous Section Next Section

Discussion

While starting to use C++, we all learn quite quickly that header files like



// avoid defining entities with external linkage in a header


int fudgeFactor;


string hello("Hello, world!");


void foo() {/* … */}



are liable to cause link-time errors complaining of duplicate symbols as soon as such a header is included by more than one source file. The reason is simple: Each source file actually defines and allocates space for fudgeFactor and hello and foo's body, and when the time comes to put it all together (linking), the linker is faced with several symbols bearing the same name and competing for visibility.

The solution is simpleput just the declarations in the header:



extern int fudgeFactor;


extern string hello;


void foo();                 // "extern" is optional with function declarations



The actual definitions go in a single implementation file:



int fudgeFactor;


string hello("Hello, world!");


void foo() {/* … */ }



Also, do not definite namespace-level static entities in a header. For example:



// avoid defining entities with static linkage in a header


static int fudgeFactor;


static string hello("Hello, world!");


static void foo() {/* … */ }



Such misuse of static is more dangerous than just defining global entities in the header. With global entities, at least the linker is liable to promptly uncover the duplication. But static data and functions are legal to duplicate because the compiler recognizes that you are asking for a private copy in each source file. So, if you define static data and static functions in a header and include that header in 50 files, the bodies of the functions and the space for the data will be duplicated 50 times in the final executable code (except in the presence of some modern linkers that merge together identical function bodies and const data when such merging is safe). Needless to say, global data (such as the static fudgeFactor) is not really global because each source file ends up manipulating its own copy, independent of all other copies in the program.

Don't try to get around this by (ab)using unnamed namespaces in header files because the effects would be just as unpleasant:



// in a header file, this is just as bad as static


namespace {


 int fudgeFactor;


 string hello("Hello, world!");


 void foo() {/* … */ }


}



    Team LiB
    Previous Section Next Section