TTree::Fill() doesn't save pointed TClonesArray in subobj?

Hi everybody,

I’m sorry, but I’m stlli in trouble with my ROOT based reconstruction program.

I have the following user defined class structure:

[code]class MyEvent : public TObject {
public:
MyEvent() {}; // def ctor, never called
MyEvent(non_root_class* c) : se(c->SubClass()) {…}; // working (copy) ctor

private:
MySubEvent se;

};

class MySubEvent : public TObject {
public:
MySubEvent() { hits = new TClonesArray(“MyHit”, 0); } // def ctor, nevre called
MySubEvent(non_root_subclass* sc) { hits = new TClonesArray(“MyHit”, 10000); … /* loop over hits and fill TClonesArray / } // working (copy) ctor
~MySubEvent () {delete hits; }
private:
TClonesArray
hits
};

class MyHit : public TObject {
private:
/* only basic types */
}
[/code]

and I want to write it into a tree with a single SPLITTED branch:

[code]MyEvent ev_ptr = 0;
TTree
mytree = new TTree(“mytree”);
mytree->Branch(“mybranch”, “MyEvent”, &ev_ptr);

for (… /loop over events/) {
ev_ptr = new MvEvent(non_root_class* c);
mytree->Fill();
delete ev_ptr;
}
[/code]

The TTree is then written to a TFile.

As you can see I need to create and descruct the Event every time, because the ctor is the only way to fill it together with its sub elements. I assume this is legal since TTree->Branch() must recieve a ptr to a ptr to Event.
If this is not correct please tell me.

The problem is that when I read the file, TClonesArray is empty (has size 0). Commenting the “delete ev_ptr;” above would solve (I tried) the problem but is obviously not feasible because it can be a hard mem leak.
I tried to call the TTree::Branch after the first Event is constructed but nothing changed.
I guess the TTree::Fill() doesn’t actually write pointed TClonesArray to buffer but just saves the pointer, so if this is deleted the TClonesArray is not written. Am I correct?
I thought I had found a (ugly) work around by allocating the Event on the stack:

for (... /*loop over events*/) { MyEvent ev(non_root_class* c); ev_ptr = &ev; mytree->Fill(); }

but this worked only before I introduced the “delete hits” in the ~MySubEvent() dtor; after that, it gives a segfault at Fill() time (not on the first event and not in 100% of cases).

Is there something wrong in what I’m attempting to?

One more question: I’m using ROOT v3.05/07 but when I read the with ROOT v4.00 STL containers are supported with splitting, I rushed to tried it out. Unfortunatly I wasn’t successful, I tried to replace my TClonesArray* with
[ul]
std:vector vec;
std:vector vec;
std:vector<MyHit
> vec;
std:vector<MyHit*> *vec;
[/ul]
but with none of the 4 I get a browsable/drawable Branch as I can get with the TClonesArray. Why?

Thanks in advance for the help
Davide

Hi,

for (... /*loop over events*/) { ev_ptr = new MvEvent(non_root_class* c); mytree->Fill(); delete ev_ptr; }
When the branch is first filled, it caches the information about the object location (in particular the TClonesArray). The TTree is not informed that the object has been deleted and still used the old addresses.
You have to alternative. The slower alternative is to reset the addresses:

for (... /*loop over events*/) { ev_ptr = new MvEvent(non_root_class* c); mytree->SetBranchAddress("mybranch",&ev_ptr); mytree->Fill(); delete ev_ptr; }
The faster alternative is to replace the new/delete by a Clear/Copy. Maybe something like:

for (... /*loop over events*/) { *ev_ptr = *c; // of ev_ptr->CopyFrom(c); mytree->SetBranchAddress("mybranch",&ev_ptr); mytree->Fill(); ev_ptr->Clear(); }

Only

should result in a split of the vector … and only when the file is wrote with ROOT 4.00 and above.

Cheers,
Philippe.

Dear Phil,

thanks a lot for your help. It has been precious as usual.
It’s really a pity this problem with addresses, but I guess it comes out of speed considerations.
I tried the slow alternative and it proved to be really slow (a factor of 3 on the tree size I have now).
The fast alternative (reusing the same event area) is what wanted to avoid, but it looks like the only possibility now.

I tried again the std::vector<> in ROOT 4.00/04 and indeed it is splitted, but only is you place it directly in the Event class.
If, like in my case, you place it in sub object it is not split. :frowning:
Does anybody know if it is planned to be implemented in one of next releases?

Thanks again, bye
Davide

What do you mean bu ‘place in sub object’ (there are many way of doing such a thing :slight_smile: ).? Can you send me a specific example?

Cheers,
Philippe.

well, I mean what I wrote in my initial post.
The code you may found up there is pretty detailed example, I hope.
I simply tried to replace the TClonesArray* with the std::vector<> (not a pointer!) in the MySubEvent class and it is not split as the TClonesArray* is.
If still not clear, just let me know.
Thanks, bye
Davide

Hi,

I can reproduce the issue. I am working on a solution (eta sometime next week).

Cheers,
Philippe.

Hi,

This problem is now corrected in ROOT 4.00/07.

Cheers,
Philippe.

thanks a lot Philippe, I’m away till the 20th.
I’ll give it a try as soon as I’m back.
Have a nice weekend, bye
Davide