[ROOT] behaviour of non-persistent data members in object read from TTree with custom or automatic streamer

From: Frankland John (frankland@ganil.fr)
Date: Fri Sep 26 2003 - 14:29:39 MEST


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