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