Hi Rene, Thanks for your reply. I understand that one approach is more efficient than the other, but I still think there is a problem in the second case and this has more general application than the Event example. It appears to me that the TTree::Branch method intention is to delete the internally constructed Event object and resets the event ptr to 0 on output, and in fact I do see the event ptr reset to 0, but the Event destructor is not invoked before this. For example, modifying the second test script to print the event ptrs before & after: { gSystem -> Load("libEvent.so"); TFile* file = new TFile("test.root","RECREATE"); TTree* tree = new TTree("Event","Event tree"); Event* event = 0; cout << "Create Event tree branch, event = " << event << endl; TBranch *branch = tree->Branch("event", "Event", &event, 64000,99); cout << "Done with branch create, event = " << event << endl; } yields this: root [0] .x testEvent2.C Create Event tree branch, event = 0 Event constructor Done with branch create, event = 0 root[1] Thanks again for your help. -Sue Rene Brun wrote: >Hi Sue, > >The current behaviour is correct. >If you have : Event* event = new Event(); >TTree::Branch uses the existing object to organize the sub branches. >If you have: Event* event = 0; >TTree::Branch must create an object via the default constructor. >This object is not deleted when exiting the branch constructor > -because most of the time the default object created may be used for filling. > -if it was deleted, you will have to create one and call SetBranchAddress. >For this reason, it is always more convenient > -to create an object before calling TTree::Branch > -to set the pointer to 0 when reading the Tree. >This is the recommended process in our Event example. > >Rene brun > > >Sue Kasahara wrote: > > >>Hi root talk, >>I've discovered what I think is a bug in the TTree::Branch method: >> virtual TBranch *Branch(const char *name, const char *classname, >>void *addobj, Int_t bufsize=32000, Int_t splitlevel=99); >>which is that if I pass it the address of a null ptr, the internally >>constructed object of class "classname" is not properly destructed >>before exiting the method. >>I can illustrate the problem with the test/Event example, which I've >>altered only slightly to print two messages: one when the Event >>constructor is >>invoked, and one when the Event destructor is invoked. >>If I execute the following script in a root session: >>{ >> >>gSystem -> Load("libEvent.so"); >> >>TFile* file = new TFile("test.root","RECREATE"); >>TTree* tree = new TTree("Event","Event tree"); >> >>Event* event = new Event(); >>cout << "Create Event tree branch " << endl; >>TBranch *branch = tree->Branch("event", "Event", &event, 64000,99); >>cout << "Done with branch create " << endl; >>if ( event ) delete event; event = 0; >> >>} >> >>I receive the expected result: >>root [0] .x testEvent.C >>Event constructor >>Create Event tree branch >>Done with branch create >>Event destructor >>root[1] >> >>but if I execute this script: >>{ >> >>gSystem -> Load("libEvent.so"); >> >>TFile* file = new TFile("test.root","RECREATE"); >>TTree* tree = new TTree("Event","Event tree"); >> >>Event* event = 0; >>cout << "Create Event tree branch " << endl; >>TBranch *branch = tree->Branch("event", "Event", &event, 64000,99); >>cout << "Done with branch create " << endl; >> >>} >> >>root [0] .x testEvent2.C >>Create Event tree branch >>Event constructor >>Done with branch create >>root[1] >> >>which is unexpected because the Event destructor is never invoked. >>I'm attaching the modified Event.cxx that I use in this example. I'm using >>root cvs from today 5 Dec 2004, (I also observed the problem with root from >>23 Oct 2004.), on linux with gcc 3.2.3. >>Thanks for your help, >>-Sue >> >> -------------------------------------------------------------------------------- >>// @(#)root/test:$Name: $:$Id: Event.cxx,v 1.27 2004/01/25 20:33:32 brun Exp $ >>// Author: Rene Brun 19/08/96 >> >>//////////////////////////////////////////////////////////////////////// >>// >>// Event and Track classes >>// ======================= >>// >>// The Event class is a naive/simple example of an event structure. >>// public: >>// char fType[20]; >>// char *fEventName; //run+event number in character format >>// Int_t fNtrack; >>// Int_t fNseg; >>// Int_t fNvertex; >>// UInt_t fFlag; >>// Double32_t fTemperature; >>// Int_t fMeasures[10]; >>// Double32_t fMatrix[4][4]; >>// Double32_t *fClosestDistance; //[fNvertex] indexed array! >>// EventHeader fEvtHdr; >>// TClonesArray *fTracks; >>// TRefArray *fHighPt; //array of High Pt tracks only >>// TRefArray *fMuons; //array of Muon tracks only >>// TRef fLastTrack; //pointer to last track >>// TRef fHistoWeb; //EXEC:GetHistoWeb reference to an histogram in a TWebFile >>// TH1F *fH; >>// TBits fTriggerBits; //Bits triggered by this event. >>// >>// The EventHeader class has 3 data members (integers): >>// public: >>// Int_t fEvtNum; >>// Int_t fRun; >>// Int_t fDate; >>// >>// >>// The Event data member fTracks is a pointer to a TClonesArray. >>// It is an array of a variable number of tracks per event. >>// Each element of the array is an object of class Track with the members: >>// private: >>// Float_t fPx; //X component of the momentum >>// Float_t fPy; //Y component of the momentum >>// Float_t fPz; //Z component of the momentum >>// Float_t fRandom; //A random track quantity >>// Float_t fMass2; //The mass square of this particle >>// Float_t fBx; //X intercept at the vertex >>// Float_t fBy; //Y intercept at the vertex >>// Float_t fMeanCharge; //Mean charge deposition of all hits of this track >>// Float_t fXfirst; //X coordinate of the first point >>// Float_t fXlast; //X coordinate of the last point >>// Float_t fYfirst; //Y coordinate of the first point >>// Float_t fYlast; //Y coordinate of the last point >>// Float_t fZfirst; //Z coordinate of the first point >>// Float_t fZlast; //Z coordinate of the last point >>// Double32_t fCharge; //Charge of this track >>// Double32_t fVertex[3]; //Track vertex position >>// Int_t fNpoint; //Number of points for this track >>// Short_t fValid; //Validity criterion >>// Int_t fNsp; //Number of points for this track with a special value >>// Double32_t *fPointValue; //[fNsp] a special quantity for some point. >>// TBits fTriggerBits; //Bits triggered by this track. >>// >>// An example of a batch program to use the Event/Track classes is given >>// in this directory: MainEvent. >>// Look also in the same directory at the following macros: >>// - eventa.C an example how to read the tree >>// - eventb.C how to read events conditionally >>// >>// During the processing of the event (optionally) also a large number >>// of histograms can be filled. The creation and handling of the >>// histograms is taken care of by the HistogramManager class. >>// >>//////////////////////////////////////////////////////////////////////// >>#include <iostream> >>using namespace std; >> >>#include "TRandom.h" >>#include "TDirectory.h" >>#include "TProcessID.h" >> >>#include "Event.h" >> >>ClassImp(EventHeader) >>ClassImp(Event) >>ClassImp(Track) >>ClassImp(HistogramManager) >> >>TClonesArray *Event::fgTracks = 0; >>TH1F *Event::fgHist = 0; >> >>//______________________________________________________________________________ >>Event::Event() >>{ >> // Create an Event object. >> // When the constructor is invoked for the first time, the class static >> // variable fgTracks is 0 and the TClonesArray fgTracks is created. >> >> cout << "Event constructor " << endl; >> >> if (!fgTracks) fgTracks = new TClonesArray("Track", 1000); >> fTracks = fgTracks; >> fHighPt = new TRefArray; >> fMuons = new TRefArray; >> fNtrack = 0; >> fH = 0; >> Int_t i0,i1; >> for (i0 = 0; i0 < 4; i0++) { >> for (i1 = 0; i1 < 4; i1++) { >> fMatrix[i0][i1] = 0.0; >> } >> } >> for (i0 = 0; i0 <10; i0++) fMeasures[i0] = 0; >> for (i0 = 0; i0 <20; i0++) fType[i0] = 0; >> fClosestDistance = 0; >> fEventName = 0; >> fWebHistogram.SetAction(this); >>} >> >>//______________________________________________________________________________ >>Event::~Event() >>{ >> cout << "Event destructor " << endl; >> >> Clear(); >> if (fH == fgHist) fgHist = 0; >> delete fH; fH = 0; >> delete fHighPt; fHighPt = 0; >> delete fMuons; fMuons = 0; >> delete [] fClosestDistance; >> if (fEventName) delete [] fEventName; >>} >> >>//______________________________________________________________________________ >>void Event::Build(Int_t ev, Int_t arg5, Float_t ptmin) { >> char etype[20]; >> Float_t sigmat, sigmas; >> gRandom->Rannor(sigmat,sigmas); >> Int_t ntrack = Int_t(arg5 +arg5*sigmat/120.); >> Float_t random = gRandom->Rndm(1); >> >> //Save current Object count >> Int_t ObjectNumber = TProcessID::GetObjectCount(); >> Clear(); >> fHighPt->Delete(); >> fMuons->Delete(); >> >> Int_t nch = 15; >> if (ev >= 100) nch += 3; >> if (ev >= 10000) nch += 3; >> if (fEventName) delete [] fEventName; >> fEventName = new char[nch]; >> sprintf(fEventName,"Event%d_Run%d",ev,200); >> sprintf(etype,"type%d",ev%5); >> SetType(etype); >> SetHeader(ev, 200, 960312, random); >> SetNseg(Int_t(10*ntrack+20*sigmas)); >> SetNvertex(Int_t(1+20*gRandom->Rndm())); >> SetFlag(UInt_t(random+0.5)); >> SetTemperature(random+20.); >> >> for(UChar_t m = 0; m < 10; m++) { >> SetMeasure(m, Int_t(gRandom->Gaus(m,m+1))); >> } >> for(UChar_t i0 = 0; i0 < 4; i0++) { >> for(UChar_t i1 = 0; i1 < 4; i1++) { >> SetMatrix(i0,i1,gRandom->Gaus(i0*i1,1)); >> } >> } >> >> fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1))); >> fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1))); >> fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1))); >> >> // Create and Fill the Track objects >> for (Int_t t = 0; t < ntrack; t++) AddTrack(random,ptmin); >> >> //Restore Object count >> //To save space in the table keeping track of all referenced objects >> //we assume that our events do not address each other. We reset the >> //object count to what it was at the beginning of the event. >> TProcessID::SetObjectCount(ObjectNumber); >>} >> >>//______________________________________________________________________________ >>Track *Event::AddTrack(Float_t random, Float_t ptmin) >>{ >> // Add a new track to the list of tracks for this event. >> // To avoid calling the very time consuming operator new for each track, >> // the standard but not well know C++ operator "new with placement" >> // is called. If tracks[i] is 0, a new Track object will be created >> // otherwise the previous Track[i] will be overwritten. >> >> TClonesArray &tracks = *fTracks; >> Track *track = new(tracks[fNtrack++]) Track(random); >> //Save reference to last Track in the collection of Tracks >> fLastTrack = track; >> //Save reference in fHighPt if track is a high Pt track >> if (track->GetPt() > ptmin) fHighPt->Add(track); >> //Save reference in fMuons if track is a muon candidate >> if (track->GetMass2() < 0.11) fMuons->Add(track); >> return track; >>} >> >>//______________________________________________________________________________ >>void Event::Clear(Option_t * /*option*/) >>{ >> fTracks->Clear("C"); //will also call Track::Clear >> fHighPt->Delete(); >> fMuons->Delete(); >>} >> >>//______________________________________________________________________________ >>void Event::Reset(Option_t * /*option*/) >>{ >>// Static function to reset all static objects for this event >>// fgTracks->Delete(option); >> >> delete fgTracks; fgTracks = 0; >> fgHist = 0; >>} >> >>//______________________________________________________________________________ >>void Event::SetHeader(Int_t i, Int_t run, Int_t date, Float_t random) >>{ >> fNtrack = 0; >> fEvtHdr.Set(i, run, date); >> if (!fgHist) fgHist = new TH1F("hstat","Event Histogram",100,0,1); >> fH = fgHist; >> fH->Fill(random); >>} >> >>//______________________________________________________________________________ >>void Event::SetMeasure(UChar_t which, Int_t what) { >> if (which<10) fMeasures[which] = what; >>} >> >>//______________________________________________________________________________ >>void Event::SetRandomVertex() { >> // This delete is to test the relocation of variable length array >> if (fClosestDistance) delete [] fClosestDistance; >> if (!fNvertex) { >> fClosestDistance = 0; >> return; >> } >> fClosestDistance = new Double32_t[fNvertex]; >> for (Int_t k = 0; k < fNvertex; k++ ) { >> fClosestDistance[k] = gRandom->Gaus(1,1); >> } >>} >> >>//______________________________________________________________________________ >>Track::Track(const Track &orig) : TObject(orig) >>{ >> // Copy a track object >> >> fPx = orig.fPx; >> fPy = orig.fPy; >> fPz = orig.fPx; >> fRandom = orig.fRandom; >> fMass2 = orig.fMass2; >> fBx = orig.fBx; >> fBy = orig.fBy; >> fMeanCharge = orig.fMeanCharge; >> fXfirst = orig.fXfirst; >> fXlast = orig.fXlast; >> fYfirst = orig.fYfirst; >> fYlast = orig.fYlast; >> fZfirst = orig.fZfirst; >> fZlast = orig.fZlast; >> fCharge = orig.fCharge; >> >> fVertex[0] = orig.fVertex[0]; >> fVertex[1] = orig.fVertex[1]; >> fVertex[2] = orig.fVertex[2]; >> fNpoint = orig.fNpoint; >> fNsp = orig.fNsp; >> if (fNsp) { >> fPointValue = new Double32_t[fNsp]; >> for(int i=0; i<fNsp; i++) { >> fPointValue[i] = orig.fPointValue[i]; >> } >> } else { >> fPointValue = 0; >> } >> fValid = orig.fValid; >> >> fTriggerBits = orig.fTriggerBits; >> >>} >> >>//______________________________________________________________________________ >>Track::Track(Float_t random) : TObject(),fTriggerBits(64) >>{ >> // Create a track object. >> // Note that in this example, data members do not have any physical meaning. >> >> Float_t a,b,px,py; >> gRandom->Rannor(px,py); >> fPx = px; >> fPy = py; >> fPz = TMath::Sqrt(px*px+py*py); >> fRandom = 1000*random; >> if (fRandom < 10) fMass2 = 0.106; >> else if (fRandom < 100) fMass2 = 0.8; >> else if (fRandom < 500) fMass2 = 4.5; >> else if (fRandom < 900) fMass2 = 8.9; >> else fMass2 = 9.8; >> gRandom->Rannor(a,b); >> fBx = 0.1*a; >> fBy = 0.1*b; >> fMeanCharge = 0.01*gRandom->Rndm(1); >> gRandom->Rannor(a,b); >> fXfirst = a*10; >> fXlast = b*10; >> gRandom->Rannor(a,b); >> fYfirst = a*12; >> fYlast = b*16; >> gRandom->Rannor(a,b); >> fZfirst = 50 + 5*a; >> fZlast = 200 + 10*b; >> fCharge = Double32_t(Int_t(3*gRandom->Rndm(1)) - 1); >> >> fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1))); >> fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1))); >> fTriggerBits.SetBitNumber((UInt_t)(64*gRandom->Rndm(1))); >> >> fVertex[0] = gRandom->Gaus(0,0.1); >> fVertex[1] = gRandom->Gaus(0,0.2); >> fVertex[2] = gRandom->Gaus(0,10); >> fNpoint = Int_t(60+10*gRandom->Rndm(1)); >> fNsp = Int_t(3*gRandom->Rndm(1)); >> if (fNsp) { >> fPointValue = new Double32_t[fNsp]; >> for(int i=0; i<fNsp; i++) { >> fPointValue[i] = i+1; >> } >> } else { >> fPointValue = 0; >> } >> fValid = Int_t(0.6+gRandom->Rndm(1)); >>} >> >>//______________________________________________________________________________ >>void Track::Clear(Option_t * /*option*/) >>{ >> fTriggerBits.Clear(); >> delete [] fPointValue; >> fPointValue=0; >>} >> >>//______________________________________________________________________________ >>HistogramManager::HistogramManager(TDirectory *dir) >>{ >> // Create histogram manager object. Histograms will be created >> // in the "dir" directory. >> >> // Save current directory and cd to "dir". >> TDirectory *saved = gDirectory; >> dir->cd(); >> >> fNtrack = new TH1F("hNtrack", "Ntrack",100,575,625); >> fNseg = new TH1F("hNseg", "Nseg",100,5800,6200); >> fTemperature = new TH1F("hTemperature","Temperature",100,19.5,20.5); >> fPx = new TH1F("hPx", "Px",100,-4,4); >> fPy = new TH1F("hPy", "Py",100,-4,4); >> fPz = new TH1F("hPz", "Pz",100,0,5); >> fRandom = new TH1F("hRandom", "Random",100,0,1000); >> fMass2 = new TH1F("hMass2", "Mass2",100,0,12); >> fBx = new TH1F("hBx", "Bx",100,-0.5,0.5); >> fBy = new TH1F("hBy", "By",100,-0.5,0.5); >> fMeanCharge = new TH1F("hMeanCharge","MeanCharge",100,0,0.01); >> fXfirst = new TH1F("hXfirst", "Xfirst",100,-40,40); >> fXlast = new TH1F("hXlast", "Xlast",100,-40,40); >> fYfirst = new TH1F("hYfirst", "Yfirst",100,-40,40); >> fYlast = new TH1F("hYlast", "Ylast",100,-40,40); >> fZfirst = new TH1F("hZfirst", "Zfirst",100,0,80); >> fZlast = new TH1F("hZlast", "Zlast",100,0,250); >> fCharge = new TH1F("hCharge", "Charge",100,-1.5,1.5); >> fNpoint = new TH1F("hNpoint", "Npoint",100,50,80); >> fValid = new TH1F("hValid", "Valid",100,0,1.2); >> >> // cd back to original directory >> saved->cd(); >>} >> >>//______________________________________________________________________________ >>HistogramManager::~HistogramManager() >>{ >> // Clean up all histograms. >> >> // Nothing to do. Histograms will be deleted when the directory >> // in which tey are stored is closed. >>} >> >>//______________________________________________________________________________ >>void HistogramManager::Hfill(Event *event) >>{ >> // Fill histograms. >> >> fNtrack->Fill(event->GetNtrack()); >> fNseg->Fill(event->GetNseg()); >> fTemperature->Fill(event->GetTemperature()); >> >> for (Int_t itrack = 0; itrack < event->GetNtrack(); itrack++) { >> Track *track = (Track*)event->GetTracks()->UncheckedAt(itrack); >> fPx->Fill(track->GetPx()); >> fPy->Fill(track->GetPy()); >> fPz->Fill(track->GetPz()); >> fRandom->Fill(track->GetRandom()); >> fMass2->Fill(track->GetMass2()); >> fBx->Fill(track->GetBx()); >> fBy->Fill(track->GetBy()); >> fMeanCharge->Fill(track->GetMeanCharge()); >> fXfirst->Fill(track->GetXfirst()); >> fXlast->Fill(track->GetXlast()); >> fYfirst->Fill(track->GetYfirst()); >> fYlast->Fill(track->GetYlast()); >> fZfirst->Fill(track->GetZfirst()); >> fZlast->Fill(track->GetZlast()); >> fCharge->Fill(track->GetCharge()); >> fNpoint->Fill(track->GetNpoint()); >> fValid->Fill(track->GetValid()); >> } >>} >> >>
This archive was generated by hypermail 2b29 : Sun Jan 02 2005 - 05:50:10 MET