Home | News | Documentation | Download

Read object from TBranch using new custom streamer

Hello
I have a TTree with an unsplit branch containing objects of MyClass. When the TTree was written,
MyClass had an automatic Streamer generated by rootcint (#pragma link C++ class MyClass+; in LinkDef.h)
Now MyClass has been updated and has a custom Streamer.
When I read the old MyClass objects from the TTree with the new class version,
the custom Streamer is never called.
How can I force the use of my MyClass::Streamer?
Thanks in advance
John
PS. v5.34/35

Hi John,

If the branch was not split, it should be automatically calling the custom streamer. If the branch is split then it can not (ever) call the custom streamer. Solving this issue was one the reason we introduced the I/O customization rules, most of what is typically done in a custom streamer can be done with a rule which will be called when reading back a split branch.

Cheers,
Philippe.

Oh dear. Thanks for the reply Philippe. Here is an example you can try:

(after renaming Makefile.txt to Makefile; site wouldn’t allow upload as “Makefile”)

make FLAGS=-DWRITE ./tree_io make clean make FLAGS="-DREAD -DCUSTOM_STREAMER" ./tree_io Info in <MyClass::Streamer>: In the custom streamer x=0 x=1 x=2 x=3 x=4

The message from the Streamer comes when I read back an object written directly in the file.
The 5 objects read from the TTree show no message.
What am I doing wrong?
Makefile.txt (477 Bytes)
LinkDef.h (219 Bytes)
MyClass.cpp (348 Bytes)
MyClass.h (278 Bytes)
tree_io.cpp (774 Bytes)

Hi,

This is indeed a bug … During the write the TTree essentially recorded that the class did not have a custom stream and during the reading, it ‘forgets’ to double check. This needs to be fixed.

In the meantime, you can solve the problem (at write time :frowning: ), by creating the branch with: t->Branch("myclass", "MyClass",(void*)&m, 32000, -1);

Better yet, you can try to re-implement your custom streamer in term of I/O rules.

Cheers,
Philippe.

OK, thanks a lot Philippe. I don’t know about the new (?) I/O rules, are they in the user’s guide?
What we basically need to do is add a call to a member function of the class in the ‘reading’ streamer
just before ReadClassBuffer, like this:

[code]void MyClass::Streamer(TBuffer &R__b)
{
// Stream an object of class MyClass.

if (R__b.IsReading()) {
Clear(); // call Clear, avoid enormous memory leak
R__b.ReadClassBuffer(MyClass::Class(),this);
} else {
R__b.WriteClassBuffer(MyClass::Class(),this);
}
}
[/code]
Is that possible with I/O rules?

Hi,

What is the content of Clear? Are the member touched transient?

Philippe.

No. Clear() is like this:

void KVFAZIARawEvent::Clear(Option_t*) { fSignals->Clear(); fValues->Clear(); }

where the two persistent member variables are declared as:

class KVFAZIARawEvent : public TObject { protected: TClonesArray* fSignals;//-> array where signals are storred KVNameValueList* fValues;//-> list of values

What does KVNameValueList::Clear do?

Cheers,
Philippe.

Hi Philippe
KVNameValueList is basically a THashList containing TNamed objects.
The list owns its objects, KVNameValueList::Clear calls the THashList::Clear
method which deletes all the TNamed objects.
Cheers
John

Hi John,

For KVNameValueList, it’s custom streamer should be doing the Clear (for example, this is the case for THashList where clear is called in TList::Streamer).

TClonesArray’s should also ‘Clear’ properly by default. What is special about the Signals?

Cheers,
Philippe.

PS. For I/O rules, see for example root.cern.ch/root/SchemaEvolution.pdf

Hi John,

I solved the problem with the ignored ‘new’ custom Streamer in the master branch.

Cheers,
Philippe.

Thanks a lot!