- Default constructors - ROOT I/O requires all the (persistent) classes
to have public default constructors. These contructors
need to be called in
order to create transient representation of the objects being read. The
default constructors need to initialize all the pointers. Non-null
pointers are regarded by ROOT as valid pointers (are not
overwritten when reading the file), leading to a memory access
violation in the case of uninitialized pointers.
In some of the cases (for instance
G4LogicalVolume) the default constructor can also perform the
registration of the objects to some store (G4LogicalVolumeStore). This
is possible as long as the only information registered is the address
of the object (all the other data is yet not available at that time).
- Typedefs to annonymous structs - in G4PolyPhiFace.hh the
following syntax is used:
typedef struct
{
...
...
} G4PolyPhiFaceVertex;
this, being a typedef to an annonymous struct cannot be processed by
lcgdict and creates problems at the level of the dictionary (the
destructor name is incorrect). The simple solution for that is to
replace the above typedef by:
struct G4PolyPhiFaceEdge
{
...
...
};
This change, however, is not necessary when the struct has members
which are only of fundamental types, like for instance, in
G4PolyconeSide.hh:
typedef struct
{
G4double r, z;
} G4PolyconeSideRZ;
In such a case, the destructor is not generated in the dictionary, and the
problem does not occur.
- Missing default constructor initializing pointers -
G4PolyPhiFaceEdge (defined in G4PolyPhiFace.hh) contains two pointers
which need to be initialized by the default constructor. The complete
struct definition should then have the following form:
struct G4PolyPhiFaceEdge
{
G4PolyPhiFaceEdge(): v0(0), v1(0) {}; // default constructor
G4PolyPhiFaceVertex *v0, *v1; // Corners
G4double tr, tz, // Unit vector along edge
length; // Length of edge
G4ThreeVector norm3D; // 3D edge normal vector
};
- Sizes of arrays - for any variable length arrays of fundamental
types which are declared as, for instance
class X
{
...
int N;
double* A;
...
}
and instanciated in the code using the new operator
...
A = new double[N];
...
ROOT needs to be 'informed' (otherwise there is no way it can figure
out what is the size of the structure the pointer is pointing to)
about the fact that the variable N
describes the lenght of the array. In order to do so, one should add
the following comment in the class definition
class X
{
...
int N;
double* A;//[N]
...
}
Note that the variable N must be declared before the array and that
there should be no spaces between '//' and '['.
Most likely a possible, alternative solution would be to add a new feature to
lcgdict tool allowing
to specify the length of the arrays in the selection files. This would
eliminate the need of adding //[size] comments in the G4 header files.
- Fixed size arrays instanciated using 'new' operator - in a few
places (G4IonisParamElm, G4IonisParamMat) there are fixed size arrays
instaciated using 'new' operator, namely
class G4IonisParamElm{
...
double* fShellCorrectionVector;
...
};
....
fShellCorrectionVector = new double[3];
....
In order to have ROOT to handle it properly, an additional variable is
needed
class G4IonisParamElm{
...
int N;
double* fShellCorrectionVector;
...
};
....
N = 3;
fShellCorrectionVector = new double[N];//[N]
....
Probably, it could be possible to avoid that by having ROOT to
understand comments specifying fixed lenghts like //[3] (or any other
syntax). Again, it should be possible to specify all this at the level
of the selection file, not touching the G4 headers.
- Variable lenght arrays of objects (not fundamental types) - for the
time being ROOT cannot handle arrays of non-fundamental types like
class A
{
...
int N;
MyClass* C;
...
};
...
C = new MyClass[N];
...
The only solution to that for the moment is to change such arrays to std::vectors
class A
{
...
int N;
std::vector C;
...
};
...
C.resize(N);
...
(as well as to use iterators in all the loops).
It was said, however, that ROOT in the (near?) future should be able
to support arrays of non-fundamental type, which would make the
changes to std::vectors not necessary.
- In G4VCSGfaceted there is a member
G4VCSGface **faces;
instanciated as
faces = new G4VCSGface*[numFace];
This (double *) is not supported by ROOT. It is ambiguous from the
point of view of persistency. It can be regarded as a pointer to an
array or as an array of pointers (which is the case for this class).
The only solution here, I guess, is to change it to
std::vector<G4VCSGface*> faces;
and
faces.resize(numFace);
as well as to use iterators in all the loops.
- G4Material destructor uses the index in the material table to
sets the appropriate pointer (in the material table) to 0. This
creates a problem when using ROOT I/O (while reading). The requirement
is that it should be possible to instanciate and delete objects
without streaming in all the values of the data members (in particular
fIndexInTable). In other words the destructor should not do anything
in case the fIndexInTable was not read from the file. The change
therefore is to have the default constructor to initialize it to some
unphysical (very large) value
G4Material::G4Material():fNumberOfComponents(0), fNumberOfElements(0), theElementVector(0),
fImplicitElement(false), fMassFractionVector(0), fAtomsVector(0),
fMaterialPropertiesTable(0), fIndexInTable(10000000),
VecNbOfAtomsPerVolume(0), fIonisation(0), fSandiaTable(0)
{}
and in the destructor to check whether its value was changed or not
...
if (fIndexInTable != 10000000) theMaterialTable[fIndexInTable] = 0;
...