Egbert Nierop (MVP for IIS) wrote:
> Hi,
>
[quoted text clipped - 10 lines]
>
> Thanks...
C and C++ have a rule known as the "one definition rule". Under this
rule, each function may only have one definition in a particular
program. If you have two different source files that include the header
you mention, then your program will actually have two definitions of
AllocString available to it, one in each of the source files, which
causes the linker to complain (when linking, it tries to resolve all
references to a function to the definition of that function, but you
have two definitions, so it doesn't know which one to pick).
Static "fixes" the problem since then the definition of AllocString is
private to the two source files that use it, but you end up with two
independent copies of AllocString, one in each source file - in effect,
you now have two different AllocString functions that happen to share
the same name.
Other fixes include:
- Move the _definition_ of AllocString out of the header and into a
source file. Obviously the declaration should stay in the header.
- Put "inline" in front of the function declaration.
Note that #pragma once/include guards/etc. don't help here, since that
only ensures that a header is only included once for a particular source
file, not across the whole program.
Tom
Duane Hebert - 05 May 2005 11:07 GMT
> Egbert Nierop (MVP for IIS) wrote:
> Note that #pragma once/include guards/etc. don't help here, since that
> only ensures that a header is only included once for a particular source
> file, not across the whole program.
Though I'm not sure about the pragma, why wouldn't include guards
work? They're based on compiler directives. If the define is true,
it should jump to the #endif. If this weren't true, how could templates
work when their definitions are all in the header file? Does the
compiler treat non class templates differently somehow?
Mihajlo Cvetanovic - 05 May 2005 13:20 GMT
> Though I'm not sure about the pragma, why wouldn't include guards
> work? They're based on compiler directives. If the define is true,
> it should jump to the #endif. If this weren't true, how could templates
> work when their definitions are all in the header file? Does the
> compiler treat non class templates differently somehow?
This is the linker error. In the following example the linker will
notice that problematic function is defined twice.
First.cpp
---------
#include "ProblematicHeader.h"
Second.cpp
----------
#include "ProblematicHeader.h"
Carl Daniel [VC++ MVP] - 05 May 2005 14:15 GMT
>> Egbert Nierop (MVP for IIS) wrote:
>
[quoted text clipped - 10 lines]
> work when their definitions are all in the header file? Does the
> compiler treat non class templates differently somehow?
Yes - Templates are special in that the compiler is required to merge
multiple definitions of a template function or template class, as long as
they're all the same (otherwise it's an ODR - One Definition Rule -
violation). While templates need not be all inline (though they frequently
are), they get essentially the same treatment from the compiler as an inline
function that wasn't in fact inlined (since the compiler is free to ignore
any inline suggestion that you give, and routinely does so in debub builds).
-cd
Duane Hebert - 06 May 2005 00:17 GMT
> Yes - Templates are special in that the compiler is required to merge
> multiple definitions of a template function or template class, as long as
[quoted text clipped - 3 lines]
> function that wasn't in fact inlined (since the compiler is free to ignore
> any inline suggestion that you give, and routinely does so in debub builds).
Thanks. But I'm still not seeing why header guards don't work. Once
a header guard is passed, shouldn't the code in the header be read
once and the next time it's seen shouldn't the #ifndef/#endif take it
out of the picture? Is this something that happens only for free
functions? If you put them in a namespace does this solve the
problem?
Like I said before, I don't remember ever having free functions
defined in a header file (except for templates) I'm just curious
why this would be a problem. Thanks for the explanation.
Tamas Demjen - 06 May 2005 00:55 GMT
> Thanks. But I'm still not seeing why header guards don't work. Once
> a header guard is passed, shouldn't the code in the header be read
> once
Once per unit, not once per project. If you define a function in a
header file H.h:
#pragma once
int MyFunc() { return 0; }
you can still include it from two different units:
//A.cpp
#include "H.h"
//B.cpp
#include "H.h"
which results in duplicate definition within the same project. A.obj
will contain MyFunc, and B.obj will contain it too, thus the linker will
complain about double definition. It's a linker error, not a compiler error.
Rule of thumb: Every non-member function implemented in the header file
must be explicitly declared inline, or the implementation must be moved
to the .cpp file, otherwise you run the risk of double definition.
Tom
Tamas Demjen - 06 May 2005 01:00 GMT
> Rule of thumb: Every non-member function implemented in the header file
> must be explicitly declared inline, or the implementation must be moved
> to the .cpp file, otherwise you run the risk of double definition.
Correction: Every non-member non-template function [...]
Tom
Duane Hebert - 06 May 2005 01:42 GMT
> which results in duplicate definition within the same project. A.obj
> will contain MyFunc, and B.obj will contain it too, thus the linker will
[quoted text clipped - 3 lines]
> must be explicitly declared inline, or the implementation must be moved
> to the .cpp file, otherwise you run the risk of double definition.
Thanks. I never realized that. I normally put the definitions in cpp files
anyway. BTW, what's this #pragma once? I imagine that it functions
like header guards but is it portable?
Carl Daniel [VC++ MVP] - 06 May 2005 03:12 GMT
> BTW, what's this #pragma once? I imagine that it functions
> like header guards but is it portable?
Yes, it does.
No, it's not.
-cd
Duane Hebert - 06 May 2005 11:30 GMT
> > BTW, what's this #pragma once? I imagine that it functions
> > like header guards but is it portable?
>
> Yes, it does.
>
> No, it's not.
Thanks.
Egbert Nierop \(MVP for IIS\) - 05 May 2005 11:11 GMT
> Egbert Nierop (MVP for IIS) wrote:
>> Hi,
[quoted text clipped - 32 lines]
> file. Obviously the declaration should stay in the header.
> - Put "inline" in front of the function declaration.
Thanks...
This solved my 'problem' :)
I did not know, the compiler worked like this. So I only include the .h file
while the .cpp 'seems' unreferenced in the project.
> Note that #pragma once/include guards/etc. don't help here, since that
> only ensures that a header is only included once for a particular source
> file, not across the whole program.
>
> Tom