Hi all-
I am currently using TClonesArrays extensively in our event data structure. The problem is, you can’t use them deeper than top-level without deleting them at the end of the event loop. For that matter you can’t use any object that allocated memory which means you almost certainly can’t have any other class inside (e.g. vector, string, etc. all allocate memory within ) unless you know exactly what’s going on in that class. This is a problem for non-pointer member objects, e.g.:
class MyClass : public TObject {
// Can't put this in a TClonesArray
// without calling TClonesArray::Delete() on each
// event loop
protected:
std::vector<double> fMyData;
};
Anyways, I know way to deal with this is either to give something of static size (for example an array of defined size), call TClonesArray::Delete(), or actively delete objects in Clear(), but this sort of defeats the point of a TClonesArray altogether. My question is, is this really necessary? For example:
The way to get a new object in a TClonesArray is to call this new function to place memory in the location defined by TClonesArray:
where a is of course a TClonesArray. This calls the object’s constructor, but places all the memory in a particular location. When the TClonesArray is cleared with Clear(“C”), it calls the Clear functions of all the TTrack members and resets its own size to 0. No destructors are called. However, when you insert an object via the new method above, the constructor is called again, etc…
My question is, if there is an object that has already been allocated in the TClonesArray, why not just grab a pointer to that old object? That is, your code would look like:
TClonesArray a;
track = new(a[a.GetEntriesFast()]) TTrack(x,y,z,...);
...
a.Clear('C');
// any subsequent calls would be like:
if ( a.WasConstructorCalledAt(i) ) {
track = a.GetOld(i); // Function would return
}
track->fX = myx;
// etc...
which would get an old (but cleared and presumably in a pristine virgin state!) object if the constructor for that object has already been called. In principle, one could add a function to TClonesArray:
which would return an old (but cleared) object or a new object if size is less than i.
Anyways, I leave out a lot of implementation details, one thing that would need to be done in Clear() is resetting all the bits and unique id from TObject correctly (which get set normally during the constructor calls).
Am I missing something? This seems like it would speed things up a lot for classes which allocate data. What it would do is force a user to ensure that in the Clear functions, the allocated data is cleared (or reset to an acceptable state). I don’t think this is far beyond what is already required of users coding with TClonesArrays. For some users, this might not make a difference, but for example for users of vectors and other TClonesArrays, this would make a big difference. Both vectors and TClonesArrays can be cleared fast without deallocation of data.
Cheers,
Mike