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