On Wed, Jan 19, 2005 at 03:55:19PM -0600, Jason Dusek wrote:
In the FAQ, they discuss a problem with multiple inclusions of a header where global symbols are defined:
The problem has NOTHING to do with multiple inclusions of a header. The actual problem is declaration of global variables in different compilation units by inclusion a _single_ header file, like this: // file bogus.h #ifndef VARGS_BOGUS_H #define VARGS_BOGUS_H #include <ginac/ginac.h> const GiNaC::symbol x("x"); #endif // file fun1.cpp #include <ginac/ginac.h> #include "bogus.h" const GiNaC::ex fun1() { return x; } // file fun2.cpp #include <ginac/ginac.h> #include "bogus.h" const GiNaC::ex fun2() { return x; } // file main.cpp #include <iostream> #include <ginac/ginac.h> using namespace std; using namespace GiNaC; extern const ex fun1(); extern const ex fun2(); int main(int argc, char* argv) { ex bogus = fun1() - fun2(); // print expression as a tree cout << tree << bogus << endl; return 0; } On my system, this program will print add @0x805ef88, hash=0xb7e7ae1a, flags=0x3, nops=2 x (symbol) @0x805eda8, serial=2, hash=0x670d3697, flags=0xf, domain=0 1 (numeric) @0x804fde8, hash=0x160af41d, flags=0xf ----- x (symbol) @0x805ed70, serial=1, hash=0x79ba0000, flags=0xf, domain=0 -1 (numeric) @0x804fc58, hash=0xd60af41d, flags=0xf ===== So, `bogus' is _not_ zero, because there are two _different_ symbols (with the same print-name x): one of them was defined in the file fun1.cpp, another -- in fun2.cpp. Note, that in this example header file "bogus.h" gets included only once.
================================================ Q: I have various modules, some global variables and...
A: ...and you are getting weird results with symbols not being identical? Imagine this situation: A file globals.h declares symbol x("x"). Two other modules #include "globals.h", do something with symbol x and return an expression ex containing the symbol to the caller (e.g. to main()). When the caller combines the two expressions there are really two different symbols both with the same print-name x. This may cause terms like x-x to stay around which will never be simplified to 0 because the system has no knowledge that the two symbols are supposed to be the same. How should it? After all the declarations really happend in different compilation units! ================================================ Can include guards solve this problem?
No, they can't.
Do I *have* to make that evil factory initializer thingy?
You might use something like // file bogus.h #ifndef VARGS_GLOBAL_X_H #define VARGS_GLOBAL_X_H #include <ginac/ginac.h> extern GiNaC::symbol x; #endif // file bogus.cpp #include <ginac/ginac.h> #include "bogus.h" using namespace GiNaC; symbol x("x"); // file fun1.cpp #include <ginac/ginac.h> #include "bogus.h" const GiNaC::ex fun1() { return x; } // file fun2.cpp #include <ginac/ginac.h> #include "bogus.h" const GiNaC::ex fun2() { return x; } // file main.cpp #include <iostream> #include <ginac/ginac.h> using namespace std; using namespace GiNaC; extern const ex fun1(); extern const ex fun2(); int main(int argc, char* argv) { ex bogus = fun1() - fun2(); // print expression as a tree cout << tree << bogus << endl; // will print zero return 0; } But (IMHO) such a code is even more evil :) Best regards, Alexei.