ROOT logo
ROOT » CORE » CONT » TClonesArray

class TClonesArray: public TObjArray


An array of clone (identical) objects. Memory for the objects
stored in the array is allocated only once in the lifetime of the
clones array. All objects must be of the same class. For the rest
this class has the same properties as TObjArray.

To reduce the very large number of new and delete calls in large
loops like this (O(100000) x O(10000) times new/delete):

TObjArray a(10000);
while (TEvent *ev = (TEvent *)next()) {      // O(100000) events
for (int i = 0; i < ev->Ntracks; i++) {   // O(10000) tracks
a[i] = new TTrack(x,y,z,...);


}

a.Delete();
}

One better uses a TClonesArray which reduces the number of
new/delete calls to only O(10000):

TClonesArray a("TTrack", 10000);
while (TEvent *ev = (TEvent *)next()) {      // O(100000) events
for (int i = 0; i < ev->Ntracks; i++) {   // O(10000) tracks
new(a[i]) TTrack(x,y,z,...);


}

a.Delete(); // or a.Clear() or a.Clear("C")
}

To reduce the number of call to the constructor (especially useful
if the user class requires memory allocation), the object can be
added (and constructed when needed) using ConstructedAt which only
calls the constructor once per slot.

TClonesArray a("TTrack", 10000);
while (TEvent *ev = (TEvent *)next()) {      // O(100000) events
for (int i = 0; i < ev->Ntracks; i++) {   // O(10000) tracks
TTrack *track = (TTrack*)a.ConstructedAt(i);
track->Set(x,y,z,....);


}

a.Clear(); // or a.Clear("C");
}

Note: the only supported way to add objects to a TClonesArray is
via the new with placement method or the ConstructedAt method.
The other Add() methods ofTObjArray and its base classes are not
allowed.

Considering that a new/delete costs about 70 mus on a 300 MHz HP,
O(10^9) new/deletes will save about 19 hours.

  NOTE 1

 C/C++ offers the possibility of allocating and deleting memory.
 Forgetting to delete allocated memory is a programming error called a
 "memory leak", i.e. the memory of your process grows and eventually
 your program crashes. Even if you *always* delete the allocated
 memory, the recovered space may not be efficiently reused. The
 process knows that there are portions of free memory, but when you
 allocate it again, a fresh piece of memory is grabbed. Your program
 is free from semantic errors, but the total memory of your process
 still grows, because your program's memory is full of "holes" which
 reduce the efficiency of memory access; this is called "memory
 fragmentation". Moreover new / delete are expensive operations in
 terms of CPU time.

 Without entering into technical details, TClonesArray allows you to
 "reuse" the same portion of memory for new/delete avoiding memory
 fragmentation and memory growth and improving the performance by
 orders of magnitude. Every time the memory of the TClonesArray has
 to be reused, the Clear() method is used. To provide its benefits,
 each TClonesArray must be allocated *once* per process and disposed
 of (deleted) *only when not needed any more*.

 So a job should see *only one* deletion for each TClonesArray,
 which should be Clear()ed during the job several times. Deleting a
 TClonesArray is a double waste. Not only you do not avoid memory
 fragmentation, but you worsen it because the TClonesArray itself
 is a rather heavy structure, and there is quite some code in the
 destructor, so you have more memory fragmentation and slower code.

  NOTE 2


 When investigating misuse of TClonesArray, please make sure of the following:

    * Use Clear() or Clear("C") instead of Delete(). This will improve
      program execution time.
    * TClonesArray object classes containing pointers allocate memory.
      To avoid causing memory leaks, special Clear("C") must be used
      for clearing TClonesArray. When option "C" is specified, ROOT
      automatically executes the Clear() method (by default it is
      empty contained in TObject). This method must be overridden in
      the relevant TClonesArray object class, implementing the reset
      procedure for pointer objects.
    * To reduce memory fragmentation, please make sure that the
      TClonesArrays are not destroyed and created on every event. They
      must only be constructed/destructed at the beginning/end of the
      run.


Function Members (Methods)

public:
TClonesArray()
TClonesArray(const TClonesArray& tc)
TClonesArray(const char* classname, Int_t size = 1000, Bool_t call_dtor = kFALSE)
TClonesArray(const TClass* cl, Int_t size = 1000, Bool_t call_dtor = kFALSE)
virtual~TClonesArray()
voidAbsorbObjects(TClonesArray* tc)
voidAbsorbObjects(TClonesArray* tc, Int_t idx1, Int_t idx2)
voidTObject::AbstractMethod(const char* method) const
virtual voidTObjArray::Add(TObject* obj)
virtual voidAddAfter(const TObject*, TObject*)
virtual voidTCollection::AddAll(const TCollection* col)
virtual voidAddAt(TObject*, Int_t)
virtual voidAddAtAndExpand(TObject*, Int_t)
virtual Int_tAddAtFree(TObject*)
virtual voidAddBefore(const TObject*, TObject*)
virtual voidAddFirst(TObject*)
virtual voidAddLast(TObject*)
TObject*AddrAt(Int_t idx)
voidTCollection::AddVector(TObject* obj1)
virtual TObject*TObjArray::After(const TObject* obj) const
virtual voidTObject::AppendPad(Option_t* option = "")
Bool_tTCollection::AssertClass(TClass* cl) const
virtual TObject*TObjArray::At(Int_t i) const
virtual TObject*TObjArray::Before(const TObject* obj) const
virtual Int_tTObjArray::BinarySearch(TObject* obj, Int_t upto = kMaxInt)
virtual voidTCollection::Browse(TBrowser* b)
voidBypassStreamer(Bool_t bypass = kTRUE)
Bool_tCanBypassStreamer() const
Int_tTCollection::Capacity() const
static TClass*Class()
virtual const char*TObject::ClassName() const
virtual voidClear(Option_t* option = "")
virtual TObject*TCollection::Clone(const char* newname = "") const
virtual Int_tTCollection::Compare(const TObject* obj) const
virtual voidCompress()
TObject*ConstructedAt(Int_t idx)
TObject*ConstructedAt(Int_t idx, Option_t* clear_options)
Bool_tTCollection::Contains(const char* name) const
Bool_tTCollection::Contains(const TObject* obj) const
virtual voidTObject::Copy(TObject& object) const
virtual voidDelete(Option_t* option = "")
virtual Int_tTObject::DistancetoPrimitive(Int_t px, Int_t py)
virtual voidTCollection::Draw(Option_t* option = "")
virtual voidTObject::DrawClass() constMENU
virtual TObject*TObject::DrawClone(Option_t* option = "") constMENU
virtual voidTCollection::Dump() const
static voidTCollection::EmptyGarbageCollection()
virtual voidTObject::Error(const char* method, const char* msgfmt) const
virtual voidTObject::Execute(const char* method, const char* params, Int_t* error = 0)
virtual voidTObject::Execute(TMethod* method, TObjArray* params, Int_t* error = 0)
virtual voidTObject::ExecuteEvent(Int_t event, Int_t px, Int_t py)
virtual voidExpand(Int_t newSize)
virtual voidExpandCreate(Int_t n)
virtual voidExpandCreateFast(Int_t n)
virtual voidTObject::Fatal(const char* method, const char* msgfmt) const
virtual TObject*TObjArray::FindObject(const char* name) const
virtual TObject*TObjArray::FindObject(const TObject* obj) const
virtual TObject*TObjArray::First() const
static voidTCollection::GarbageCollect(TObject* obj)
TClass*GetClass() const
static TCollection*TCollection::GetCurrentCollection()
virtual Option_t*TObject::GetDrawOption() const
static Long_tTObject::GetDtorOnly()
virtual Int_tTObjArray::GetEntries() const
Int_tTObjArray::GetEntriesFast() const
virtual const char*TObject::GetIconName() const
virtual Int_tTObjArray::GetLast() const
virtual const char*TCollection::GetName() const
virtual char*TObject::GetObjectInfo(Int_t px, Int_t py) const
TObject**TObjArray::GetObjectRef() const
virtual TObject**TObjArray::GetObjectRef(const TObject* obj) const
static Bool_tTObject::GetObjectStat()
virtual Option_t*TObject::GetOption() const
virtual Int_tTCollection::GetSize() const
virtual const char*TObject::GetTitle() const
virtual UInt_tTObject::GetUniqueID() const
virtual Int_tTCollection::GrowBy(Int_t delta) const
virtual Bool_tTObject::HandleTimer(TTimer* timer)
virtual ULong_tTCollection::Hash() const
virtual Int_tTObjArray::IndexOf(const TObject* obj) const
virtual voidTObject::Info(const char* method, const char* msgfmt) const
virtual Bool_tTObject::InheritsFrom(const char* classname) const
virtual Bool_tTObject::InheritsFrom(const TClass* cl) const
virtual voidTObject::Inspect() constMENU
voidTObject::InvertBit(UInt_t f)
virtual TClass*IsA() const
Bool_tTCollection::IsArgNull(const char* where, const TObject* obj) const
virtual Bool_tTObjArray::IsEmpty() const
virtual Bool_tTObject::IsEqual(const TObject* obj) const
virtual Bool_tTCollection::IsFolder() const
Bool_tTObject::IsOnHeap() const
Bool_tTCollection::IsOwner() const
virtual Bool_tTCollection::IsSortable() const
virtual Bool_tTSeqCollection::IsSorted() const
Bool_tTObject::IsZombie() const
virtual TObject*TObjArray::Last() const
Int_tTSeqCollection::LastIndex() const
Int_tTObjArray::LowerBound() const
virtual voidTCollection::ls(Option_t* option = "") const
virtual TIterator*TObjArray::MakeIterator(Bool_t dir = kIterForward) const
virtual TIterator*TCollection::MakeReverseIterator() const
voidTObject::MayNotUse(const char* method) const
Long64_tTSeqCollection::Merge(TCollection* list)
voidMultiSort(Int_t nTCs, TClonesArray** tcs, Int_t upto = kMaxInt)
TObject*New(Int_t idx)
virtual Bool_tTObject::Notify()
static Int_tTSeqCollection::ObjCompare(TObject* a, TObject* b)
voidTObject::Obsolete(const char* method, const char* asOfVers, const char* removedFromVers) const
static voidTObject::operator delete(void* ptr)
static voidTObject::operator delete(void* ptr, void* vp)
static voidTObject::operator delete[](void* ptr)
static voidTObject::operator delete[](void* ptr, void* vp)
void*TObject::operator new(size_t sz)
void*TObject::operator new(size_t sz, void* vp)
void*TObject::operator new[](size_t sz)
void*TObject::operator new[](size_t sz, void* vp)
TObject*TCollection::operator()(const char* name) const
TClonesArray&operator=(const TClonesArray& tc)
virtual TObject*&operator[](Int_t idx)
virtual TObject*operator[](Int_t idx) const
virtual voidTCollection::Paint(Option_t* option = "")
virtual voidTObject::Pop()
virtual voidTCollection::Print(Option_t* option = "") const
virtual voidTCollection::Print(Option_t* option, Int_t recurse) const
virtual voidTCollection::Print(Option_t* option, const char* wildcard, Int_t recurse = 1) const
virtual voidTCollection::Print(Option_t* option, TPRegexp& regexp, Int_t recurse = 1) const
static voidTSeqCollection::QSort(TObject** a, Int_t first, Int_t last)
static voidTSeqCollection::QSort(TObject** a, TObject** b, Int_t first, Int_t last)
static voidTSeqCollection::QSort(TObject** a, Int_t nBs, TObject*** b, Int_t first, Int_t last)
virtual voidTObjArray::Randomize(Int_t ntimes = 1)
virtual Int_tTObject::Read(const char* name)
virtual voidTObjArray::RecursiveRemove(TObject* obj)
virtual TObject*Remove(TObject* obj)
virtual voidTSeqCollection::RemoveAfter(TObject* after)
voidTCollection::RemoveAll()
virtual voidTCollection::RemoveAll(TCollection* col)
virtual TObject*RemoveAt(Int_t idx)
virtual voidTSeqCollection::RemoveBefore(TObject* before)
virtual voidTSeqCollection::RemoveFirst()
virtual voidTSeqCollection::RemoveLast()
virtual voidRemoveRange(Int_t idx1, Int_t idx2)
voidTObject::ResetBit(UInt_t f)
virtual voidTObject::SaveAs(const char* filename = "", Option_t* option = "") constMENU
virtual voidTObject::SavePrimitive(ostream& out, Option_t* option = "")
voidTObject::SetBit(UInt_t f)
voidTObject::SetBit(UInt_t f, Bool_t set)
voidSetClass(const char* classname, Int_t size = 1000)
voidSetClass(const TClass* cl, Int_t size = 1000)
voidTCollection::SetCurrentCollection()
virtual voidTObject::SetDrawOption(Option_t* option = "")MENU
static voidTObject::SetDtorOnly(void* obj)
voidTObjArray::SetLast(Int_t last)
voidTCollection::SetName(const char* name)
static voidTObject::SetObjectStat(Bool_t stat)
virtual voidSetOwner(Bool_t enable = kTRUE)
virtual voidTObject::SetUniqueID(UInt_t uid)
virtual voidShowMembers(TMemberInspector&)
virtual voidSort(Int_t upto = kMaxInt)
static voidTCollection::StartGarbageCollection()
virtual voidStreamer(TBuffer&)
voidStreamerNVirtual(TBuffer& ClassDef_StreamerNVirtual_b)
virtual voidTObject::SysError(const char* method, const char* msgfmt) const
Bool_tTObject::TestBit(UInt_t f) const
Int_tTObject::TestBits(UInt_t f) const
TObject*TObjArray::UncheckedAt(Int_t i) const
voidTSeqCollection::UnSort()
virtual voidTObject::UseCurrentStyle()
virtual voidTObject::Warning(const char* method, const char* msgfmt) const
virtual Int_tTCollection::Write(const char* name = 0, Int_t option = 0, Int_t bufsize = 0)
virtual Int_tTCollection::Write(const char* name = 0, Int_t option = 0, Int_t bufsize = 0) const
protected:
Bool_tTObjArray::BoundsOk(const char* where, Int_t at) const
virtual voidTSeqCollection::Changed()
virtual voidTObject::DoError(int level, const char* location, const char* fmt, va_list va) const
Int_tTObjArray::GetAbsLast() const
virtual const char*TCollection::GetCollectionEntryName(TObject* entry) const
voidTObjArray::Init(Int_t s, Int_t lowerBound)
voidTObject::MakeZombie()
Bool_tTObjArray::OutOfBoundsError(const char* where, Int_t i) const
virtual voidTCollection::PrintCollectionEntry(TObject* entry, Option_t* option, Int_t recurse) const
virtual voidTCollection::PrintCollectionHeader(Option_t* option) const

Data Members

public:
enum { kForgetBits
kNoSplit
kBypassStreamer
};
enum TCollection::[unnamed] { kIsOwner
kInitCapacity
kInitHashTableCapacity
};
enum TObject::EStatusBits { kCanDelete
kMustCleanup
kObjInCanvas
kIsReferenced
kHasUUID
kCannotPick
kNoContextMenu
kInvalidObject
};
enum TObject::[unnamed] { kIsOnHeap
kNotDeleted
kZombie
kBitMask
kSingleKey
kOverwrite
kWriteDelete
};
protected:
TClass*fClass!Pointer to the class
TObject**TObjArray::fCont!Array contents
TObjArray*fKeep!Saved copies of pointers to objects
Int_tTObjArray::fLastLast element in array containing an object
Int_tTObjArray::fLowerBoundLower bound of the array
TStringTCollection::fNamename of the collection
Int_tTCollection::fSizenumber of elements in collection
Bool_tTSeqCollection::fSortedtrue if collection has been sorted

Class Charts

Inheritance Inherited Members Includes Libraries
Class Charts

Function documentation

TClonesArray()
 Default Constructor.
TClonesArray(const char* classname, Int_t size = 1000, Bool_t call_dtor = kFALSE)
 Create an array of clone objects of classname. The class must inherit from
 TObject. If the class defines its own operator delete(), make sure that
 it looks like this:

    void MyClass::operator delete(void *vp)
    {
       if ((Long_t) vp != TObject::GetDtorOnly())
          ::operator delete(vp);       // delete space
       else
          TObject::SetDtorOnly(0);
    }

 The second argument s indicates an approximate number of objects
 that will be entered in the array. If more than s objects are entered,
 the array will be automatically expanded.

 The third argument is not used anymore and only there for backward
 compatibility reasons.
TClonesArray(const TClass* cl, Int_t size = 1000, Bool_t call_dtor = kFALSE)
 Create an array of clone objects of class cl. The class must inherit from
 TObject. If the class defines an own operator delete(), make sure that
 it looks like this:

    void MyClass::operator delete(void *vp)
    {
       if ((Long_t) vp != TObject::GetDtorOnly())
          ::operator delete(vp);       // delete space
       else
          TObject::SetDtorOnly(0);
    }

 The second argument, s, indicates an approximate number of objects
 that will be entered in the array. If more than s objects are entered,
 the array will be automatically expanded.

 The third argument is not used anymore and only there for backward
 compatibility reasons.
TClonesArray(const TClonesArray& tc)
 Copy ctor.
TClonesArray& operator=(const TClonesArray& tc)
 Assignment operator.
~TClonesArray()
 Delete a clones array.
void BypassStreamer(Bool_t bypass = kTRUE)
 When the kBypassStreamer bit is set, the automatically
 generated Streamer can call directly TClass::WriteBuffer.
 Bypassing the Streamer improves the performance when writing/reading
 the objects in the TClonesArray. However there is a drawback:
 When a TClonesArray is written with split=0 bypassing the Streamer,
 the StreamerInfo of the class in the array being optimized,
 one cannot use later the TClonesArray with split>0. For example,
 there is a problem with the following scenario:
  1- A class Foo has a TClonesArray of Bar objects
  2- The Foo object is written with split=0 to Tree T1.
     In this case the StreamerInfo for the class Bar is created
     in optimized mode in such a way that data members of the same type
     are written as an array improving the I/O performance.
  3- In a new program, T1 is read and a new Tree T2 is created
     with the object Foo in split>1
  4- When the T2 branch is created, the StreamerInfo for the class Bar
     is created with no optimization (mandatory for the split mode).
     The optimized Bar StreamerInfo is going to be used to read
     the TClonesArray in T1. The result will be Bar objects with
     data member values not in the right sequence.
 The solution to this problem is to call BypassStreamer(kFALSE)
 for the TClonesArray. In this case, the normal Bar::Streamer function
 will be called. The Bar::Streamer function works OK independently
 if the Bar StreamerInfo had been generated in optimized mode or not.
void Compress()
 Remove empty slots from array.
TObject * ConstructedAt(Int_t idx)
 Get an object at index 'idx' that is guaranteed to have been constructed.
 It might be either a freshly allocated object or one that had already been
 allocated (and assumingly used).  In the later case, it is the callers
 responsability to insure that the object is returned to a known state,
 usually by calling the Clear method on the TClonesArray.

 Tests to see if the destructor has been called on the object.
 If so, or if the object has never been constructed the class constructor is called using
 New().  If not, return a pointer to the correct memory location.
 This explicitly to deal with TObject classes that allocate memory
 which will be reset (but not deallocated) in their Clear()
 functions.
TObject * ConstructedAt(Int_t idx, Option_t* clear_options)
 Get an object at index 'idx' that is guaranteed to have been constructed.
 It might be either a freshly allocated object or one that had already been
 allocated (and assumingly used).  In the later case, the function Clear
 will be called and passed the value of 'clear_options'

 Tests to see if the destructor has been called on the object.
 If so, or if the object has never been constructed the class constructor is called using
 New().  If not, return a pointer to the correct memory location.
 This explicitly to deal with TObject classes that allocate memory
 which will be reset (but not deallocated) in their Clear()
 functions.
void Clear(Option_t* option = "")
 Clear the clones array. Only use this routine when your objects don't
 allocate memory since it will not call the object dtors.
 However, if the class in the TClonesArray implements the function
 Clear(Option_t *option) and if option = "C" the function Clear()
 is called for all objects in the array. In the function Clear(), one
 can delete objects or dynamic arrays allocated in the class.
 This procedure is much faster than calling TClonesArray::Delete().
 When the option starts with "C+", eg "C+xyz" the objects in the array
 are in turn cleared with the option "xyz"
void Delete(Option_t* option = "")
 Clear the clones array. Use this routine when your objects allocate
 memory (e.g. objects inheriting from TNamed or containing TStrings
 allocate memory). If not you better use Clear() since if is faster.
void Expand(Int_t newSize)
 Expand or shrink the array to newSize elements.
void ExpandCreate(Int_t n)
 Expand or shrink the array to n elements and create the clone
 objects by calling their default ctor. If n is less than the current size
 the array is shrunk and the allocated space is freed.
 This routine is typically used to create a clonesarray into which
 one can directly copy object data without going via the
 "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
void ExpandCreateFast(Int_t n)
 Expand or shrink the array to n elements and create the clone
 objects by calling their default ctor. If n is less than the current size
 the array is shrinked but the allocated space is _not_ freed.
 This routine is typically used to create a clonesarray into which
 one can directly copy object data without going via the
 "new (arr[i]) MyObj()" (i.e. the vtbl is already set correctly).
 This is a simplified version of ExpandCreate used in the TTree mechanism.
TObject * RemoveAt(Int_t idx)
 Remove object at index idx.
TObject * Remove(TObject* obj)
 Remove object from array.
void RemoveRange(Int_t idx1, Int_t idx2)
 Remove objects from index idx1 to idx2 included.
void SetClass(const TClass* cl, Int_t size = 1000)
 Create an array of clone objects of class cl. The class must inherit from
 TObject. If the class defines an own operator delete(), make sure that
 it looks like this:

    void MyClass::operator delete(void *vp)
    {
       if ((Long_t) vp != TObject::GetDtorOnly())
          ::operator delete(vp);       // delete space
       else
          TObject::SetDtorOnly(0);
    }

 The second argument s indicates an approximate number of objects
 that will be entered in the array. If more than s objects are entered,
 the array will be automatically expanded.

 NB: This function should not be called in the TClonesArray is already
     initialized with a class.
void SetClass(const char* classname, Int_t size = 1000)
void SetOwner(Bool_t enable = kTRUE)
 A TClonesArray is always the owner of the object it contains.
 However the collection its inherits from (TObjArray) does not.
 Hence this member function needs to be a nop for TClonesArray.
void Sort(Int_t upto = kMaxInt)
 If objects in array are sortable (i.e. IsSortable() returns true
 for all objects) then sort array.
void Streamer(TBuffer& )
 Write all objects in array to the I/O buffer. ATTENTION: empty slots
 are also stored (using one byte per slot). If you don't want this
 use a TOrdCollection or TList.
TObject *& operator[](Int_t idx)
 Return pointer to reserved area in which a new object of clones
 class can be constructed. This operator should not be used for
 lefthand side assignments, like a[2] = xxx. Only like,
 new (a[2]) myClass, or xxx = a[2]. Of course right hand side usage
 is only legal after the object has been constructed via the
 new operator or via the New() method. To remove elements from
 the clones array use Remove() or RemoveAt().
TObject * operator[](Int_t idx) const
 Return the object at position idx. Returns 0 if idx is out of bounds.
TObject * New(Int_t idx)
 Create an object of type fClass with the default ctor at the specified
 index. Returns 0 in case of error.
void AbsorbObjects(TClonesArray* tc)
 Directly move the object pointers from tc without cloning (copying).
 This TClonesArray takes over ownership of all of tc's object
 pointers. The tc array is left empty upon return.
void AbsorbObjects(TClonesArray* tc, Int_t idx1, Int_t idx2)
 Directly move the range of object pointers from tc without cloning
 (copying).
 This TClonesArray takes over ownership of all of tc's object pointers
 from idx1 to idx2. The tc array is re-arranged by return.
void MultiSort(Int_t nTCs, TClonesArray** tcs, Int_t upto = kMaxInt)
 Sort multiple TClonesArrays simultaneously with this array.
 If objects in array are sortable (i.e. IsSortable() returns true
 for all objects) then sort array.
TObject * AddrAt(Int_t idx)
TClass * GetClass() const
{ return fClass; }
void AddFirst(TObject* )
{ MayNotUse("AddFirst"); }
void AddLast(TObject* )
{ MayNotUse("AddLast"); }
void AddAt(TObject* , Int_t )
{ MayNotUse("AddAt"); }
void AddAtAndExpand(TObject* , Int_t )
{ MayNotUse("AddAtAndExpand"); }
Int_t AddAtFree(TObject* )
{ MayNotUse("AddAtFree"); return 0; }
void AddAfter(const TObject* , TObject* )
{ MayNotUse("AddAfter"); }
void AddBefore(const TObject* , TObject* )
{ MayNotUse("AddBefore"); }
Bool_t CanBypassStreamer() const