Monday, July 27, 2009

Avoiding multiple definition errors in C++?

Hello friends,





I was always under the impression that if I created a header file that contained:





#ifndef HEADER_H_


#define HEADER_H_





const char* foo = "Hello" ;





#endif





I could safely include this header in as many .cpp files as I wanted, and the preprocessor directives would prevent multiple inclusions?





I'm using g++, and getting "multiple definition" errors on foo when I use the above practice. I'm now assuming that the preprocessor is applied once per .cpp file -- meaning each file will only define up to one instance of foo, however, the linker will freak out when it goes to work.





What is the best way to handle this problem? I know I could just define foo in the .cpp file, but its a constant and I like to keep constants in the .h file. I've thought about making foo extern in the header, but then I still have to initalize it in the .cpp file -- How can I do this cleanly so that the initialization is done in the header?





Thanks!

Avoiding multiple definition errors in C++?
No. The preprocessor guards prevent multiple inclusion for a single compilation unit (i.e. for a single .cpp file). If you have multiple compilation units (i.e. more than one .cpp file), the definition is included once per compilation unit, which is more than once in total. This will trigger a linker error, when you try to link the various compilation units together. The problem is that a header file should never contain a definition; it should only contain declarations.








REPEAT AFTER ME:


A header file should contain declarations, only!!!





What you should put in your header file is:


extern const char* const foo;





Unlike the statement "const char* foo= ...", this does not allocate space (notice the "extern" keyword), and therefore constitutes a declaration rather than a definition.





In A SINGLE compilation unit (i.e. in just one .cpp file), write:


const char* const foo = "Hello";





This will provide the single definition that you need.








NOTE:


Using global variables like this is considered to be "bad practice." It is much better to write the following:





// Some header file


const char* getfoo();





// Some C++ file


const char* getfoo()


{


return "Hello";


}





WHY YOUR SOLUTION IS BAD PRACTICE:





Your solution is bad practice, because you clearly want to make "foo" constant; however, your code makes it possible to modify "foo". The type of "foo" should be "const char* const", not "const char*" in order to make this distinction.





In my opinion, it is best to have a function which returns the constant value, because that way it is possible for someone who does not have access to your header file to still use the constant value when dynamically linking against your code.
Reply:Are you using AIX 5.3?


If so, then you may never be able to get rid of those duplicate symbol warnings.





Your method of ifndef, define, ... endif is correct.


You should not be getting those duplicate symbol warnings.


No comments:

Post a Comment