In the FAQ, they discuss a problem with multiple inclusions of a header where global symbols are defined: ================================================ 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? Do I *have* to make that evil factory initializer thingy? -- _jason
Dear Jason, On Wed, 19 Jan 2005, Jason Dusek wrote:
Can include guards solve this problem? Do I *have* to make that evil factory initializer thingy?
The simplest way is to just declare symbols in header files (i.e., symbol x;) and to define them in one cpp-file (i.e., symbol x("x");). That is what I generally do. I am not a big fan of factories either. Best wishes, Chris
On Wed, 19 Jan 2005, I wrote:
The simplest way is to just declare symbols in header files (i.e., symbol x;) and to define them in one cpp-file (i.e., symbol x("x");). That is what I generally do. I am not a big fan of factories either.
Of course, I should have said "extern symbol x". However, using "extern ex x;" in the header file and "ex x(symbol("x"));" in the cpp file is more efficient.
using "extern ex x;" in the header file and "ex x(symbol("x"));" in the cpp file is more efficient.
Why is it more efficient? _jason On Thu, 20 Jan 2005 11:10:20 +0100 (CET), Chris Dams <C.Dams@science.ru.nl> wrote:
On Wed, 19 Jan 2005, I wrote:
The simplest way is to just declare symbols in header files (i.e., symbol x;) and to define them in one cpp-file (i.e., symbol x("x");). That is what I generally do. I am not a big fan of factories either.
Of course, I should have said "extern symbol x". However, using "extern ex x;" in the header file and "ex x(symbol("x"));" in the cpp file is more efficient.
_______________________________________________ GiNaC-list mailing list GiNaC-list@ginac.de http://thep.physik.uni-mainz.de/mailman/listinfo/ginac-list
-- _jason
Dear Jason, On Fri, 21 Jan 2005, Jason Dusek wrote:
using "extern ex x;" in the header file and "ex x(symbol("x"));" in the cpp file is more efficient.
Why is it more efficient?
Try, for instance, symbol x("x"); ex x1=x; ex x2=x; Asking the debugger what x1 and x2 are gives (gdb) print x1 $1 = {bp = {p = 0x804eb40}} (gdb) print x2 $2 = {bp = {p = 0x804ec30}} Two symbols have dynamically allocated and are considered the same because they have the same serial number. Let us now try: ex x(symbol("x")); ex x1=x; ex x2=x; Now the debugger says (gdb) print x1 $1 = {bp = {p = 0x804eb70}} (gdb) print x2 $2 = {bp = {p = 0x804eb70}} Only one symbol has been dynamically allocated. That should be more efficient. Beste wishes, Chris
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.
What if I define the symbol as a static variable in a class header? // <Evil.h> #include <one_of_everything> class Evil { public: static symbol x("x"); void showMeTheEvil() { cout << x; }; // </Evil.h> // <even_more_evil.cpp> #include <Evil.h> int main(int argc, char* argv) { Evil evil; evil.showMeTheEvil(); } // </even_more_evil.cpp> I am fine with OO evil - making a global symbol server class, for example - but I can brook no other evil! _jason On Thu, 20 Jan 2005 11:47:04 +0300, Sheplyakov Alexei <varg@theor.jinr.ru> wrote:
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.
_______________________________________________ GiNaC-list mailing list GiNaC-list@ginac.de http://thep.physik.uni-mainz.de/mailman/listinfo/ginac-list
-- _jason
Dear Jason, On Thu, 20 Jan 2005, Jason Dusek wrote:
// <Evil.h> #include <one_of_everything>
class Evil { public: static symbol x("x");
Not allowed: should be "static symbol x;" and "symbol Evil::x("x");" somewhere outside your class.
void showMeTheEvil() { cout << x;
cout << x << endl; or perhaps some people may never see the output. Also missing closing brace.
I am fine with OO evil - making a global symbol server class, for example - but I can brook no other evil!
Possible, but do you really like to type Evil::x every time you need x? What I sometimes do is to do all my calculations in the member functions of some class. Memeber funcions can access variables like x without having to write thinks like Evil::x or evil.x. In that case, I usually do not make these variables static, since there will usually only be one copy of that particular class anyway, so it does not matter. Best wishes, Chris
Hi! On Thu, 20 Jan 2005, Jason Dusek wrote:
What if I define the symbol as a static variable in a class header?
Since you're so keenly diskussing static variables, I'ld like to make sure you are aware of the static initialzation order mess in C++: <http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.11>. Never mind, if you knew this already. Regards -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
participants (4)
-
Chris Dams
-
Jason Dusek
-
Richard B. Kreckel
-
varg@theor.jinr.ru