A GlobalManager
object does some very simple management of (certain)
global values used by CoCoALib (i.e. controlled initialization and
destruction). So that the operations in CoCoALib can work properly you
should create an object of type GlobalManager
before using any other
feature of CoCoALib. Conversely, the GlobalManager
object should be
destroyed only after you have finished using CoCoALib features. An easy
way to achieve this is to create a local variable of type GlobalManager
at the start of a top level procedure (e.g. main
). See the CoCoALib
examples.
The ctor for a GlobalManager
has one (optional) argument. This
argument is used to specify whether elements of rings of the form ZZ/n
should be printed as least non-negative residues or as (symmetric) least
magnitude residues. If no preference is specified then the current default
is symmetric residues. If you want to pass an argument to the ctor then it
should be either UseNonNegResidues
or UseSymmResidues
An exception will be thrown if you attempt to create more than one
GlobalManager
object (without having destroyed all earlier
GlobalManager
s). The exception is of type CoCoA::ErrorInfo
and has error
code ERR::GlobalManager2
.
The concept of GlobalManager
was created to handle in a clean and
coherent manner (almost) all global values used by CoCoALib; in particular
it was prompted by the decision to make the ring of integers a global
value. The tricky part was ensuring the proper destruction of RingZ
before main
exits. Recall that C++ normally destroys globals after
main
has completed, and that the order of destruction cannot easily be
governed; destroying values in the wrong order can cause to the program to
crash just before it terminates. Another advantage of forcing destruction
before main
exits is that it makes debugging very much simpler
(e.g. the MemPool
object inside RingZImpl
will be destroyed
while the input and output streams are still functioning, thus allowing the
MemPool
destructor to report any anomalies). And of course, it is
simply good manners to clean up properly at the end of the program.
To implement the restriction that only one GlobalManager
may exist
at any one time, the first instruction in the ctor checks that the
global variable GlobalManager::ourGlobalDataPtr
is null. If it is
null, it is immediately set to point the object being constructed --
it is important that ourGlobalDataPtr
be set before attempting to
construct the rationals!
I chose to use std::auto_ptr
s for the data members because I needed to
have created and "registered" the ring of integers before attempting to
construct the ring of rationals. Using auto ptrs provides automatic
clean-up and allows me to be quite explicit about construction order of
data members inside the body of the ctor for GlobalManager
(though C++
construction rules also allow explicit description of the order followed
before entering the ctor body).
The two functions MakeUniqueCopyOfRingZ
and MakeUniqueCopyOfRingQ
are
supposed to be accessible only to GlobalManager
; they create the unique
copies of those two rings which will be stored in the global data. The
functions are defined in RingZ.C
and RingQ.C
respectively but do not
appear in the corresponding header files (thus supposedly making them
"inaccessible" to other users). Note that the ring representing Z must be
created and made accessible via ourGlobalDataPtr
before
MakeUniqueCopyOfRingQ
is called. I know, this is a bit dirty/delicate;
too bad, I can't see any simple and clean way of achieving what I want.
20090521 Now I think I can implement without using auto_ptr for RingZ and RingQ (making use of the order of construction of data members before entering the ctor body).
There is a potential bug in dtor for GlobalManager
: the global values are
deregistered before they are destroyed. Might it be better to use raw ptrs
and call delete
explicitly? -- this would also make the order of destruction
explicit.
Should the ctor for GlobalManager
initialize the CoCoALib i/o streams?
Perhaps the GlobalManager
ctor should accept an argument which would
cause it to create a GMPAllocator
?
You cannot print out a GlobalManager
object; is this really a bug?
Potential race condition, if you try to create two GlobalManager
s
in parallel.
Should the ctor for GlobalManager
set the globals which control
debugging and verbosity in MemPool
s?