Reading entries on a cloned TNtuple broken if cloning happened when an unrelated file was the current file
The following is a reproducer:
#include <TFile.h>
#include <TNtuple.h>
#include <iostream>
int main() {
TFile f0("o1.root");
TFile f1("o2.root");
TNtuple *B2L = f0.Get<TNtuple>("B2Lc");
std::cout << "No clone:\n";
B2L->GetEntry(0);
std::cout << "done\n";
//f0.cd(); uncommenting fixes the issue
TNtuple *B2Lc = static_cast<TNtuple *>(B2L->Clone());
f1.cd();
std::cout << "Clone:\n";
B2Lc->GetEntry(0);
std::cout << "done\n";
return 0;
}
prints
No clone:
done
Clone:
Error in <TBasket::Streamer>: The value of fKeylen is incorrect (-23644) ; trying to recover by setting it to zero
Error in <TBasket::Streamer>: The value of fObjlen is incorrect (-2020426277) ; trying to recover by setting it to zero
Error in <TBranch::GetBasket>: File: o2.root at byte:3872444835, branch:m, entry:0, badread=1, nerrors=1, basketnumber=0
done
What is the purpose of calling Clone in this and/or the original example?
Hi Philippe, I don't remember what the original use case was :/
This is a reduced reproducer, I'm sure the original use case made more sense.
Maybe, maybe not :). The practical effect of this is ('as expected').
- Copy ALL the meta data of the TTree/TNTuple
- Attach the copy of the current directory. This is the 'intended' behavior since what to "just" copy all the meta data and then use is rare. The usual case is then (as done in CloneTree) to also do:
- Reset of the accumulated information. To fix the code above, one can do:
B2Lc->SetDirectory(B2L->GetDirectory());
Oh ok, so Clone only copies the metadata and is expected to yield broken trees as the data stays behind in a different file that the cloned tree does not know how to access.
I find this confusing and error-prone, but if it is things working as intended then nothing to do here.