Re: [ROOT] behaviour of non-persistent data members in object read from TTreewith custom or automatic streamer

From: Rene Brun (Rene.Brun@cern.ch)
Date: Mon Oct 06 2003 - 12:08:11 MEST


Hi John,

Sorry for this late reply. I was scarred by the length of your message ::)

When you use a custom Streamer, the "AutoDelete" option for the
object in the branch is automatically set to kTRUE when the Tree is created.
When this option is set, the object in the branch is always deleted and
recreated
at each GetEntry. You can disable this option by calling
 TBranch::SetAutoDelete(kFALSE);
You can do this, for example in your Analysis::Notify function
when the pointer to the branch is computed

   b_b__tp = fChain->GetBranch("b__tp");
   b_b__tp->SetAutoDelete(kFALSE); //add this line

see:
http://root.cern.ch/root/htmldoc/TBranchElement.html#TBranchElement:SetAutoDelete


Rene Brun


> Frankland John wrote:
> 
> 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. Franklandtel: +33
>                      Beam Coordinator (0)231454628
>                      GANIL            fax: +33
>                      B.P. 55027       (0)231454665
>                      14076 CAEN Cedex
>                      05
> 
>     -----------------------------------------------------------------------
> //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
> 
>     -----------------------------------------------------------------------
>  [Image]



This archive was generated by hypermail 2b29 : Thu Jan 01 2004 - 17:50:16 MET