Re: Storing pointers to objects in TClonesArrays

From: Rene Brun (Rene.Brun@cern.ch)
Date: Fri Dec 18 1998 - 14:58:48 MET


Hi Nick,
This cannot work with TClonesArray, but works with a normal
TObjArray.
The logic, however, could be implemented in TClonesArray too.
I believe that having a TClonesArray supporting references
is much better.

Rene Brun


Nick West wrote:
> 
> Hi Rene,
> 
> I have to say I am a fan of TClonesArray and your suggestion:-
> 
> > We could may be add a few additional and specialized containers
> > "a la TClonesArray". I am thinking to one specially.
> > Suppose the frequent case where you have hits/tracks referencing each
> > other. Having pointers as data members of the tiny objects may
> > induce a big penalty in I/O (4 or 8 bytes required). In case
> > you always reference the same list, it may be more clever to store
> > only the index inside the list, typically saving a factor 4 or 8
> > in storage.
> 
> is a good one but reminded me of some unfinished business.  Earlier this year I
> reported a problem with pointers to objects held in TClonesArrays, but got
> side-track onto something else.  I can still reproduce the problem in that, on
> output, all such objects get written twice, and when reinput, the pointer points
> to a copy of the object, NOT the one in the TClonesArray.  I think the basic
> problem is that, in TClonesArray::Streamer, the way objects get written out is
> by:-
> 
>     fCont[i]->Streamer(b);
> 
> rather than by writing a pointer, so the pointer address is never recorded and
> so, when the pointer gets streamed, there is no entry in the map, so it
> generates another copy.   I have a trivial example that demonstrates this:-
> 
>     MyClass.cxx,MyClass.h  Define MyClass which has a TClonesArray of MyTrack
>                                   MyTrack has a pointer to another MyTrack
> 
>     test_write.cxx         Creates a TTree with a MyClass branch
>                            Creates a MyClass, prints, fills tree once and
>                            writes tree out.
> 
>     rest_read.cxx          Opens the file, reads the tree and the first event
>                            Prints it
> 
> In test_write I store 2 MyTracks in the MyClass TClonesArray and point each to
> the other.  MyClass::Print() asks each MyTrack to print itself:-
> 
> > MyClass 0x1403f4f38 contains:
> >
> > MyTrack 0x14043ff08 fPx: 1 fPy: 2 fPz: 3
> > Related track: 0x14043ffc8
> >
> > MyTrack 0x14043ffc8 fPx: 4 fPy: 5 fPz: 6
> > Related track: 0x14043ff08
> 
> as you see "Related track" of each points to the other.  However, on input in
> test_read they don't:-
> 
> > MyClass 0x1404818a8 contains:
> >
> > MyTrack 0x140480e88 fPx: 1 fPy: 2 fPz: 3
> > Related track: 0x140480ec8
> >
> > MyTrack 0x140480f48 fPx: 4 fPy: 5 fPz: 6
> > Related track: 0x140480f08
> 
> If you, or anyone else, has time to look, here are the files I am using with
> Digital UNIX V4.0D  (Rev. 878) and Root 2.00/12
> 
> >>>>>MyClass_LinkDef.h
> 
> #ifdef __CINT__
> 
> #pragma link off all globals;
> #pragma link off all classes;
> #pragma link off all functions;
> 
> #pragma link C++ class MyClass;
> #pragma link C++ class MyTrack;
> 
> #endif
> 
> >>>>>MyClass.h
> 
> #ifndef MYCLASS
> #define MYCLASS
> 
> // Trivial class with TClonesArray and pointer to object it holds.
> 
> #include "Rtypes.h"
> 
> #include "TClonesArray.h"
> 
> class MyClass : public TObject {
> 
> private:
>   TClonesArray *fMyClonesArray;           //This will hold MyTrack objects
> 
> public:
>   MyClass();
>   ~MyClass() {;}
>   void Build();
>   void Print();
> 
>    ClassDef(MyClass,1)  //Trivial class
> };
> 
> class MyTrack : public TObject {
> 
> private:
>   MyTrack *fRelatedTrack;
>   Float_t  fPx;
>   Float_t  fPy;
>   Float_t  fPz;
> 
> public:
>    MyTrack();
>    MyTrack( Float_t px, Float_t py, Float_t pz);
>   ~MyTrack() {;}
>   void AddRelatedTrack( MyTrack* t );
>   void Print();
> 
>    ClassDef(MyTrack,1)  //Trivial track class
> };
> 
> #endif
> 
> >>>>>MyClass.cxx
> 
> #include "MyClass.h"
> #include <iostream.h>
> 
> ClassImp(MyClass)
> 
>  static TClonesArray *gfMyClonesArray;           //This is the permanent copy
> 
> //______________________________________________________________________________
> 
>   MyClass::MyClass()
> 
> {
> 
>   //  Create permanent TClonesArray if required.
> 
>   if ( ! gfMyClonesArray )gfMyClonesArray = new TClonesArray("MyTrack", 2);
>   fMyClonesArray =  gfMyClonesArray;
> 
> }
> 
> //______________________________________________________________________________
> 
>   void MyClass::Build()
> 
> {
> 
>   //  Store two MyTracks.
> 
>   MyTrack *t1 = new( (*fMyClonesArray)[0] ) MyTrack(1.,2.,3.);
>   MyTrack *t2 = new( (*fMyClonesArray)[2] ) MyTrack(4.,5.,6.);
>   t1->AddRelatedTrack(t2);
>   t2->AddRelatedTrack(t1);
> 
> }
> 
> //______________________________________________________________________________
> 
>   void MyClass::Print()
> 
> {
> 
>   cout << "MyClass " << this << " contains:" << endl << endl;
>   MyTrack *t = 0;
>   for ( Int_t tk_num = 0; tk_num < fMyClonesArray->GetEntriesFast(); tk_num++) {
>     if ( t = (MyTrack*) fMyClonesArray->At(tk_num) ) t->Print();
>   }
> 
> }
> 
> ClassImp(MyTrack)
> 
> //---------------------------------------------------------------
> 
>    MyTrack::MyTrack()
> 
> {
>    fRelatedTrack = 0;
>    fPx = 0.;
>    fPy = 0.;
>    fPz = 0.;
> }
> 
> //---------------------------------------------------------------
> 
>    MyTrack::MyTrack( Float_t px, Float_t py, Float_t pz )
> 
> {
>    fRelatedTrack = 0;
>    fPx = px;
>    fPy = py;
>    fPz = pz;
> 
> }
> 
>   void MyTrack::AddRelatedTrack( MyTrack* t )
> 
> {
>   fRelatedTrack = t;
> }
> 
> //---------------------------------------------------------------
> 
>   void MyTrack::Print()
> 
> {
>   cout << "MyTrack " << this
>        << " fPx: " << fPx << " fPy: " << fPy << " fPz: " << fPz << endl;
>   cout << "Related track: " << fRelatedTrack << endl << endl;
> 
> }
> 
> >>>>>test_write.cxx
> 
> #include "TROOT.h"
> #include "TFile.h"
> #include "TTree.h"
> 
> #include "MyClass.h"
> 
> // Initialize the ROOT system
> TROOT root("test_write","Test of TClonesArray I/O with pointers");
> 
> int main(int argc, char **argv)
> {
> 
>    TFile *output_file  = new TFile( "test.root", "RECREATE");
> 
>    MyClass *myclass = new MyClass;
> 
>    TTree *tree = new TTree("T","Test of TClonesArray I/O with ponters");
>    Int_t split = 0;
>    Int_t bsize = 1000;
>    tree->Branch("myclass", "MyClass", &myclass, bsize, split);
> 
>    myclass->Build();
>    myclass->Print();
> 
>    tree->Fill();
>    output_file->Write();
>    output_file->Close();
> 
>    return 0;
> }
> 
> >>>>>test_read.cxx
> 
> #include "TROOT.h"
> #include "TFile.h"
> #include "TTree.h"
> 
> #include "MyClass.h"
> 
> // Initialize the ROOT system
> TROOT root("test_read","Test of TClonesArray I/O with pointers");
> 
> int main(int argc, char **argv)
> {
> 
>    TFile *input_file  = new TFile( "test.root", "READ");
> 
>    MyClass *myclass = new MyClass;
> 
>    TTree *tree = (TTree*)input_file->Get("T");
>    tree->SetBranchAddress("myclass", &myclass);
> 
>    tree->GetEvent( 0 );
> 
>    myclass->Print();
> 
>    input_file->Close();
> 
>    return 0;
> }



This archive was generated by hypermail 2b29 : Tue Jan 04 2000 - 00:34:41 MET