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