Getentry() returns 0

I am very confused about output of the following code:

cout << "tree->GetEntry(0) = " << tree->GetEntry(0) << endl; cout << "tree->GetEntry(0) = " << tree->GetEntry(0) << endl;

tree->GetEntry(0) = 348
tree->GetEntry(0) = 0

This makes no sense, because GetEntry(0) should return when you try to call on an entry that has already been accessed, not 0. This problem seems to be related to the fact that tree has a friend, but I really don’t understand how that affects multiple calls to GetEntry().

Does anyone understand this?

Hi,

I can not reproduce this problem, 0 should be indicating that something went wrong. Can you provide a complete running example showing the issue and which version of ROOT you are using?

Philippe

Hi,

Here is an example that reproduces the problem. After removing a lot of code to try to create a minimal example, it started crashing at the second getentry instead of returning 0. So, I think there must be some subtle memory usage problem. To run this just download both of the attached files and type root solve_problem.C+ into the command line. I am using the following root version: ROOT 5.32/00.

Thanks.

Andrew
file.root (378 KB)
solve_problem.C (1.02 KB)

Hi,

I made another example that reproduces the problem which doesn’t involve reading in a tree from a separate file:

[code]#include “TTree.h”
#include

using namespace std;

void apply_gbr(TTree *tree, const std::vectorstd::string varseb)
{

Float_t target = 0.;

TTree *friendtree = new TTree;
friendtree->Branch(“foo”,&target,“foo/F”);

for (Long64_t iev=0; ievGetEntries(); ++iev) {

friendtree->Fill();

}

tree->AddFriend(friendtree);
}

void solve_problem()
{

Float_t bar = 0;
TTree* intree = new TTree(“my_tree”,“mytree”);
intree->Branch(“bar”,&bar);
for(UInt_t i = 0; i < 100; i++){
intree->Fill();
}

std::vectorstd::string varseb;
TTree * tree = (TTree*)intree->Clone();
assert(tree);

apply_gbr(tree, varseb);

cout << "tree->GetEntry(0) = " << tree->GetEntry(0) << endl;
cout << "tree->GetEntry(0) = " << tree->GetEntry(0) << endl;

}
[/code]

Andrew

Hi,

The problem is:void apply_gbr(TTree *electron1_tree, const std::vector<std::string> /* varseb */) { Float_t target = 0.; ... friendtree->Branch("foo",&target,"foo/F"); ... electron1_tree->AddFriend(friendtree); }where upon returning the ‘friendtree’ still retain the address of the local variable ‘target’ and thus when: electron1_tree->GetEntry(0);is called and since friendtree is attached as a friend to electron1_tree, friendtree->GetEntry(0) will be called and will write data in the memory location fomerly occupied by ‘target’ with … disastrous result. To solve the problem use friendtree->ResetBranchAddresses(); at the end of apply_gbr.

On a separate not why are you copying the TChain object rather than re-using it?

Cheers,
Philippe.

PS. A few comment on improving the code sample which may be of use even in the larger context.

[code]
void apply_gbr(TTree *electron1_tree, const std::vectorstd::string &varseb)
// Prefer passing large object by const reference rather than by value (simply
// adding the ‘&’ avoid having to copy all the strings in the vector just to call this
// routine.
{

Float_t target = 0.;

// Give a name to each TTree object, a few tools do not work without it.
TTree *friendtree = new TTree(“extra”, “extra data”);

// Since this routine does not create a TFile object, prefer to explicitly
// assign its destination to avoid having it attached to the input file
friendtree->SetDirectory(0); // or SetDirectory(output_file);

friendtree->Branch(“foo”,&target,“foo/F”);
//cout << “asdfds 3” << endl;

// Especially when using a TChain, prefer using GetEntryFast and then
// checking the return value of LoadTree.
for (Long64_t iev=0; iev<electron1_tree->GetEntriesFast(); ++iev) {
Long64_t local_entry = electron1_tree->LoadTree(iev);
if (local_entry < 0) break;

friendtree->Fill();

}

electron1_tree->AddFriend(friendtree);

// Also if any addresses were set for electron1_tree, make sure to reset them also.
friendtree->ResetBranchAddresses();
}[/code]