Hello I have a problem with non-persistent data members in objects stored in a TTree when the objects in question have a custom streamer. It seems that each call to TTree::GetEntry wipes the current value of the non-persistent data member, by a call to the default ctor for the class. This behaviour is not observed when using an automatically generated streamer, even if in fact the custom streamer is nothing but a copy of the automatically generated one. I have attached some files which demonstrate the problem. I am using the 3.05/07 binary for RH9 with gcc 3.2.2 The class TestPersist has two data members, a and b. a is persistent, b non-persistent. The method TestPersist::IsOK() returns kTRUE if a > b, and kFALSE otherwise. I generate a TTree filled with TestPersist objects using the script TestPersist_Tree.C. 100 'events' are generated with "a" taking the values 0,1,2,...,99. The AnalPersist analysis class was generated from the TTree with MakeSelector. This analysis sets a "threshold" value b=50 in the Begin() method, and then fills a histogram with the value of "a" for each "event" with TestPersist::IsOK() = kTRUE. When I use an automatic streamer (rootcint -f TestPersist_Dict.cxx -c TestPersist.h) I get the result I want, i.e. a histogram which is filled from a=51 up to 99. The "b" histogram shows that the value I set in Begin() i.e. 50 is not affected by the reading of objects from the TTree, as one expects. However, with a customised streamer (rootcint -f TestPersist_Dict.cxx -c TestPersist.h-), which is in fact an exact copy of the one generated in the previous case, the "a" histogram is filled with all values from 0 to 99, and indeed this is because the value of "b" is not 50 but 0. I checked that this is due to the default ctor being called by changing the initialisation in TestPersist::TestPersist() to "b=20". In this case I find that the value of "b" is always 20. In my "real-life" problem I have no choice but to use a customised streamer. Can you tell me how to get the same behaviour for non-persistent members in this case as when using an automatic streamer ? (preferably I would like to keep the initialisation of the non-persistent members in the default ctor!!) Thankyou very much. John. PS. I made the CINT dictionary for the class using rootcint -f TestPersist_Dict.cxx -c TestPersist.h Then I compiled the class and the dictionary and built an .so: g++ -c `root-config --cflags` -oTestPersist.o TestPersist.C g++ -c `root-config --cflags` -oTestPersist_Dict.o TestPersist_Dict.cxx g++ -shared `root-config --libs` -olibTestPersist.so TestPersist.o TestPersist_Dict.o Then at the ROOT command line I did: .L libTestPersist.so .L TestPersist_Tree.C+ write_tree() in order to create and fill the TTree. Then in a new ROOT session I do: .L libTestPersist.so TFile f("test_persist.root") t1->Process("AnalPersist.C+") In the case of a customised streamer I uncommented the line #define CUSTOM_STREAMER in TestPersist.h, built the dictionary using rootcint -f TestPersist_Dict.cxx -c TestPersist.h- and then repeated all the other steps in order. -- John D. Frankland <mailto:frankland@ganil.fr> Beam Coordinator GANIL B.P. 55027 14076 CAEN Cedex 05 *tel:* +33 (0)231454628 *fax:* +33 (0)231454665 //TestPersist.h //Used to test how non-persistent data members are treated when reading //from TTrees #include "TObject.h" #define CUSTOM_STREAMER class TestPersist : public TObject { private: Int_t a;//this member is persistent Int_t b;//! this member is not persistent public: TestPersist(); virtual ~TestPersist(); void SetA(Int_t); Int_t GetA(); void SetB(Int_t); Int_t GetB(); Bool_t IsOK(); ClassDef(TestPersist,1)//Used to test how non-persistent data members are treated when reading }; //TestPersist.C #include "TestPersist.h" ClassImp(TestPersist) TestPersist::TestPersist() { a=0; b=20; } TestPersist::~TestPersist() { } void TestPersist::SetA(Int_t i) { a=i; } void TestPersist::SetB(Int_t i) { b=i; } Int_t TestPersist::GetA() { return a; } Int_t TestPersist::GetB() { return b; } Bool_t TestPersist::IsOK() { return (a > b); } /////////////////////////////////////////////////////////////////////////// #ifdef CUSTOM_STREAMER // void TestPersist::Streamer(TBuffer &R__b) { // Stream an object of class TestPersist. UInt_t R__s, R__c; if (R__b.IsReading()) { Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { } TObject::Streamer(R__b); R__b >> a; R__b.CheckByteCount(R__s, R__c, TestPersist::IsA()); } else { R__c = R__b.WriteVersion(TestPersist::IsA(), kTRUE); TObject::Streamer(R__b); R__b << a; R__b.SetByteCount(R__c, kTRUE); } } // #endif ////////////////////////////////////////////////////////////////////////////// //Write tree using TestPersist #include "TestPersist.h" #include "TTree.h" #include "TFile.h" #include "Riostream.h" void write_tree(){ TFile *f = new TFile("test_persist.root", "RECREATE"); TTree *t1 = new TTree("t1", "Tree with TestPersist objects"); TestPersist *tp = new TestPersist; t1->Branch("b__tp","TestPersist",&tp, 16000, 0); cout << "Beginning..." << endl; for(int i=0;i<100;i++){ tp->SetA(i); t1->Fill(); } cout << "Done" << endl; t1->Print(); t1->Write(); f->Close(); } ////////////////////////////////////////////////////////// // This class has been automatically generated // (Fri Sep 26 09:48:38 2003 by ROOT version3.05/07) // from TTree t1/Tree with TestPersist objects // found on file: test_persist.root ////////////////////////////////////////////////////////// #ifndef AnalPersist_h #define AnalPersist_h #include <TROOT.h> #include <TChain.h> #include <TFile.h> #include <TSelector.h> #include "TestPersist.h" class AnalPersist : public TSelector { public : TTree *fChain; //!pointer to the analyzed TTree or TChain //Declaration of leaves types TestPersist *b__tp; //List of branches TBranch *b_b__tp; //! AnalPersist(TTree *tree=0) { } ~AnalPersist() { } void Begin(TTree *tree); void Init(TTree *tree); Bool_t Notify(); Bool_t Process(Int_t entry); Bool_t ProcessCut(Int_t entry); void ProcessFill(Int_t entry); void SetOption(const char *option) { fOption = option; } void SetObject(TObject *obj) { fObject = obj; } void SetInputList(TList *input) {fInput = input;} TList *GetOutputList() const { return fOutput; } void Terminate(); ClassDef(AnalPersist,0); }; #endif #ifdef AnalPersist_cxx void AnalPersist::Init(TTree *tree) { // Set object pointer b__tp = 0; // Set branch addresses if (tree == 0) return; fChain = tree; fChain->SetMakeClass(1); fChain->SetBranchAddress("b__tp",&b__tp); } Bool_t AnalPersist::Notify() { // Called when loading a new file. // Get branch pointers. b_b__tp = fChain->GetBranch("b__tp"); return kTRUE; } #endif // #ifdef AnalPersist_cxx
This archive was generated by hypermail 2b29 : Thu Jan 01 2004 - 17:50:15 MET