Hi Sergey, As you have found, the classes TArrayF, etc do not derive from TObject, BUT they have their Streamer method. To be streamed to the output buffer, a class does not need to derive from TObject. Here are the rules: -If a class derives from TObject, rootcint can generate automatically the Streamer function if ClassDef is specified in the header file. -If a class does not derive from TObject (such as TArrayF), you can implement the Streamer function (case of TArrayF) and still use ClassDef in the header file. -If a class derives from TObject and contains a TArrayF rootcint generates the Streamer code correctly. -If a class derives from TObject and contains a pointer to a TArrayF rootcint generates a Streamer class with the statement: R__b >> pointer; This statement must be changed to: pointer->Streamer(R__b); This could be done automatically by rootcint (not implemented). -If a class derives from TObject and contains a pointer to a basic type rootcint generates the code, issuing a warning: example In your class MuTrack, I have added a member Float_t *fX; You get the message: *** Datamember MuTrack::fX: pointer to fundamental type (need manual MuTrack::Streamer includes commented statements like: //R__b.WriteArray(fX, __COUNTER__); In such case, you typically have the array length as a data member (say member fN). Simply replace the commented statement by: R__b.WriteArray(fX,fN); When you provide the function Streamer yourself, you can instruct rootcint to not generate the code for Streamer by adding the character "-" to the class name in the file LinkDef.h. Example #pragma link C++ class MuTrack-; We are currently discussing: - the possibility to derive the TArray classes from TObject - the possibility to generate automatically the code in case of a pointer to a basic type. Consider the following example Int_t fN; Float_t *fX; //[fN] array of floats with length fN If rootcint finds a reference to a data member in the comments, it could automatically generate the instruction: R__b.WriteArray(fX,fN); Now concerning your last point with TVector, your code is correct. You hit a problem in the function TVector::ResizeTo. This problem has now been fixed in our development version. Thanks for reporting it. Rene Brun Sergey Avvakumov wrote: > > Hi everybody, > > I have to say from the start, that I'm quite new to c++ and ROOT, so I'm > probably asking about some trivial things. I'm trying to use ROOT to > replace some ZEBRA data banks and the information about an event consists > of few integers and floats and a variable length array of floats. So I > wrote a small program to accomplish this, trying to follow closely > examples 'Event.h, Event.cxx, MainEvent.cxx' from $ROOTSYS/test directory. > First I wanted to make a pointer to TArrayF to be a data member of my > class "MyTrack", then I read in documentation, that for classes, not > derived from TObject (and TArray is not) 'Streamer' method is not > generated automatically, so it's not possible to write them into a file. > Then I thought I can just copy 'Event.h', having a pointer to TClonesArray > a data member and just replacing 'Tracks' with 'object numbers', i.e. > floats, derived from TObject, but there is no such thing in ROOT by > default. I got my program working using 'TObjNum' class, like the one from > 'tcollex.cxx', but because there's no such 'built-in' class, I thought > that there should be a better way to manage an array of floats. My last > try was to use a pointer to TVector as a data member, because it is an > array of floats, derived from TObject, this is how it looks: > > MuTrack.h: > > #ifndef __MuTrack__ > #define __MuTrack__ > > ////////////////////////////////////////////////////////////////////////// > // // > // MuTrack // > // // > // Class definition for storing muon track pulseheights // > // // > ////////////////////////////////////////////////////////////////////////// > > #include "TObject.h" > #include "TVector.h" > > class MuTrack : public TObject { > > private: > Int_t fLength; // Track length > Int_t fStart; // Most upstream counter of the track > Int_t fShwrLength; // Shower length of the event, muon track > // taken from > Float_t fShwrEnergy; // Shower energy > Float_t fMuEnergy; // Muon energy > TVector *fMuPulseHeights; // Vector of muon pulseheights > > static TVector* fgMuPulseHeights; > > public: > MuTrack(); // Default constructor > virtual ~MuTrack(); // Destructor > > void SetLength(Int_t n) { fLength = n; } > void SetStart(Int_t n) { fStart = n; } > void SetShwrLength(Int_t n) { fShwrLength = n; } > void SetShwrEnergy(Float_t e) { fShwrEnergy = e; } > void SetMuEnergy(Float_t e) { fMuEnergy = e; } > > void ResizeTo(Int_t n) { fMuPulseHeights->ResizeTo(n); } > void Copy(TVector& v) { fMuPulseHeights->operator=(v); } > TVector* GetMuPulseHeights() const { return fMuPulseHeights; } > > ClassDef(MuTrack,1) // Class definition macro > }; > > #endif > > ------------------------------------------------------------------------ > > MuTrack.cxx: > > #include "MuTrack.h" > #include <iostream.h> > > ClassImp(MuTrack) > > TVector* MuTrack::fgMuPulseHeights = 0; > > //___________________________________________________________________________ > > MuTrack::MuTrack() > { > // Create a MuTrack object. > // When the constructor is invoked for the first time, the class static > // variable fgMuPulseHeights is 0 and the TVector fgMuPulseHeights > // is created. > > if (!fgMuPulseHeights) fgMuPulseHeights = new TVector(84); > fMuPulseHeights = fgMuPulseHeights; > fLength = 0; > fStart = 0; > fShwrLength = 0; > fShwrEnergy = 0.0; > fMuEnergy = 0.0; > } > > MuTrack::~MuTrack () { } > > --------------------------------------------------------------------------- > > MainMuTrack.cxx : > > #include <stdlib.h> > #include <iostream.h> > > #include "TROOT.h" > #include "TFile.h" > #include "TRandom.h" > #include "TTree.h" > #include "TBranch.h" > #include "TVector.h" > > #include "MuTrack.h" > > //____________________________________________________________________________ > int main() > { > TROOT simple("simple","Example of creation of a tree"); > > Int_t nevent = 400; // by default create 400 events > Int_t comp = 1; // by default file is compressed > Int_t split = 1; // by default, split Event in sub branches > > TFile* hfile; > MuTrack* mutrack; > TTree* tree; > > Int_t nb = 0; > Int_t ev; > Int_t bufsize; > > // Create a new ROOT binary machine independent file. > // Note that this file may contain any kind of ROOT objects, histograms, > // pictures, graphics objects, detector geometries, tracks, events, etc.. > // This file is now becoming the current directory. > hfile = new TFile("Event.root","RECREATE","TTree benchmark ROOT file"); > hfile->SetCompressionLevel(comp); > > // Create one event > mutrack = new MuTrack(); > > // Create a ROOT Tree and one superbranch > tree = new TTree("T","An example of a ROOT tree"); > tree->SetAutoSave(1000000); // autosave when 1 Mbyte written > bufsize = 256000; > if (split) bufsize /= 4; > tree->Branch("event", "MuTrack", &mutrack, bufsize,split); > > // Write out 'nevent' random events. > for (ev = 0; ev < nevent; ev++) > { > cout << "Event " << ev << endl; > Int_t length = (Int_t)(50*gRandom->Rndm(1)+1); > Int_t start = (Int_t)(80*gRandom->Rndm(1)+1); > Int_t shwrlength = (Int_t)(10*gRandom->Rndm(1)+1); > Float_t shwrenergy = gRandom->Rndm(1)*200.0; > Float_t muenergy = gRandom->Rndm(1)*90.0; > > mutrack->SetLength(length); > mutrack->SetStart(start); > mutrack->SetShwrLength(shwrlength); > mutrack->SetShwrEnergy(shwrenergy); > mutrack->SetMuEnergy(muenergy); > > TVector* vector = new TVector(length); > for (Int_t i = 0; i < length; i++) > { > Float_t ph = gRandom->Rndm(1)*90.0; > vector->operator()(i) = ph; > } > > mutrack->ResizeTo(length); > mutrack->Copy(*vector); > delete vector; > nb += tree->Fill(); //fill the tree > } > > hfile->Write(); > tree->Print(); > > hfile->Close(); > return 0; > } > --------------------------------------------------------------------------- > > This program works, but occasionally I it prints out error messages: > > CustomReAlloc2: oldsize != size > > I sort of figured out that these errors are from resizing vector > *fMuPulseHeights, the memory checker reports an error despite, > that MuTrack() constructor 'reserves' enough memory, with > fgMuPulseHeights = new TVector(84), to hold the largest > possible vector. What I don't understand is why this error > is not printed every time the size of *fMuPulseHeights gets > increased, but only occasionally. > > So my questions are - first, how to fix this program, eliminating > these memory errors, and second what is the 'best' way to have an > array of floats as a data member of the class, so that it's 'easy' to > write objects of this class into a root file? > > Thank you very much, especially to those, who read the entire posting. > > Sergei Avvakumov > avva@fnal.gov
This archive was generated by hypermail 2b29 : Tue Jan 04 2000 - 00:34:39 MET