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
. At the moment the
ctor for GlobalManager
is not threadsafe; it is the user's
responsibility to avoid trying to create several instances simultaneously.
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
(and also the field of rationals). The tricky part was ensuring the
orderly destruction of RingZ
and RingQ
before main
exits.
Recall that C++ normally destroys globals after main
has completed, and
that the order of destruction of globals 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.
The ctor for GlobalManager
is fairly delicate: e.g. the functions
it calls cannot use the functions RingZ() and RingQ() since they will not
work before the GlobalManager
is registered.
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).
The dtor for GlobalManager
checks that RingZ
and RingQ
are not
referred to by any other values (e.g. ring elements which have been
stored in global variables). A rude message is printed on cerr
if
the reference counts are too high, and a program crash is likely once
the GlobalManager
has been destroyed.
20100930 The private copies of RingZ
and RingQ
are now direct
members, previously they were owned via auto_ptr
s. The new
implementation feels cleaner, but has to include the definitions of
ring
and FractionField
.
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?
Ctor for GlobalManager
is NOT THREADSAFE.
Should the ctor for GlobalManager
set the globals which control
debugging and verbosity in MemPool
s?