-
Couldn't load subscription status.
- Fork 1.4k
[Tree] Delete virtual copy and copy assignment methods in TTree #19227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Test Results 22 files 22 suites 3d 21h 59m 6s ⏱️ For more details on these failures, see this check. Results for commit 099cfa9. ♻️ This comment has been updated with latest results. |
|
Tangentially related: #9252 |
|
Note that |
| std::unique_ptr<TTree> tClone{static_cast<TTree*>(const_cast<TTree*>(t)->CloneTree())}; | ||
| tClone->SetDirectory(nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider setting gDirectory to nullptr (via the TContext) to ensure that the TTree is really in memory.
| std::unique_ptr<TTree> tClone{static_cast<TTree*>(const_cast<TTree*>(t)->CloneTree())}; | |
| tClone->SetDirectory(nullptr); | |
| { | |
| TDirectory::TContext ctx{nullptr}; | |
| std::unique_ptr<TTree> tClone{static_cast<TTree*>(const_cast<TTree*>(t)->CloneTree())}; | |
| } |
but humm ... the previous code and the new code are doing different things (not clear what the 'real' intent is or should have been).
old: Copy just the TTree data members themselves and attach the copy to the same file:
net effect: There is 2 concurrent ways to look at the same data in the same file. Each copy of the TTree can have their own branch address and their own TTreeCache. They don't affect each other (no change in address and no changing where the cursor is).
new: Copy the tree and all its data .. but in the same file (if it is writeable) well actually in whatever file is current This is very slow if the TTree is big. The 2 trees do not affect each others but they also have duplicated (potential large) data.
proposed: Load all the data in memory after possibly a slow copy. This may or may not fit in memory. (To speeds the copy up, one could consider attaching to a TMemFile).
So really the essential question before deciding which way to go is to understand what was the intent/point of the cloning of the meta data and what are the performance and memory usage limitation that this routine needs to fit in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| std::unique_ptr<TTree> tClone{static_cast<TTree*>(const_cast<TTree*>(t)->CloneTree())}; | |
| tClone->SetDirectory(nullptr); | |
| std::unique_ptr<TTree> tClone{static_cast<TTree*>(t->GetDirectory()->CloneObject(t)); |
is another option ...
tree/tree/src/TTree.cxx
Outdated
|
|
||
| TObject *TTree::Clone(const char *) const | ||
| { | ||
| throw std::runtime_error("TObject::Clone() is not supported by TTree! Use TTree::CloneTree()."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: I think this is the first exception thrown in this file :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with Philippe and I think it shouldn't be implemented this way, rather via
Error("Clone", "Not implemented, use XXXXXXX instead.");
9cf5898 to
fb16d02
Compare
| // of the original, it tears it down at destruction time! | ||
| auto deleter = [](TTree* tree){tree->SetDirectory(nullptr); delete tree;}; | ||
| std::unique_ptr<TTree, decltype(deleter)> tClone(static_cast<TTree*>(t->Clone()), deleter); | ||
| std::unique_ptr<TTree, decltype(deleter)> tClone{static_cast<TTree*>(t->GetDirectory()->CloneObject(t)), deleter}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the fundamental difference between tree->Clone and tree->GetDirectory()->CloneObject(tree) that makes the latter ok but the first not?
tree/tree/src/TTree.cxx
Outdated
|
|
||
| TObject *TTree::Clone(const char *) const | ||
| { | ||
| throw std::runtime_error("TObject::Clone() is not supported by TTree! Use TTree::CloneTree()."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with Philippe and I think it shouldn't be implemented this way, rather via
Error("Clone", "Not implemented, use XXXXXXX instead.");
7566084 to
3291911
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this work! I do not disagree with the goal of this PR, but before approval I wanted to clarify a point
From what I can see, this PR disallows calling TTree::Clone and TTree::Copy, but in practice we are still cloning TTree ourselves in our own code in two ways:
- via
TDirectory::CloneObject - by calling the base class method
TNamed::Clone
I just want to make sure that before we go ahead we are aware of what we are doing and think wether there could be better alternatives. Do we need to clone the TTree in those occasions? If so, why don't we use CloneTree? At least I believe we should add some comments inplace.
| "TH1D": ("h", "h", 10, 0, 10), | ||
| "TH1K": ("h", "h", 10, 0, 10), | ||
| "TProfile": ("h", "h", 10, 0, 10), | ||
| "TH2C": ("h", "h", 10, 0, 10, 10, 0, 10), | ||
| "TH2S": ("h", "h", 10, 0, 10, 10, 0, 10), | ||
| "TH2I": ("h", "h", 10, 0, 10, 10, 0, 10), | ||
| "TH2L": ("h", "h", 10, 0, 10, 10, 0, 10), | ||
| "TH2F": ("h", "h", 10, 0, 10, 10, 0, 10), | ||
| "TH2D": ("h", "h", 10, 0, 10, 10, 0, 10), | ||
| "TH2Poly": ("h", "h", 10, 0, 10, 10, 0, 10), | ||
| "TH2PolyBin": tuple(), | ||
| "TProfile2D": ("h", "h", 10, 0, 10, 10, 0, 10), | ||
| "TProfile2PolyBin": tuple(), | ||
| "TProfile2Poly": ("h", "h", 10, 0, 10, 10, 0, 10), | ||
| "TH3C": ("h", "h", 10, 0, 10, 10, 0, 10, 10, 0, 10), | ||
| "TH3S": ("h", "h", 10, 0, 10, 10, 0, 10, 10, 0, 10), | ||
| "TH3I": ("h", "h", 10, 0, 10, 10, 0, 10, 10, 0, 10), | ||
| "TH3L": ("h", "h", 10, 0, 10, 10, 0, 10, 10, 0, 10), | ||
| "TH3F": ("h", "h", 10, 0, 10, 10, 0, 10, 10, 0, 10), | ||
| "TH3D": ("h", "h", 10, 0, 10, 10, 0, 10, 10, 0, 10), | ||
| "TProfile3D": ("h", "h", 10, 0, 10, 10, 0, 10, 10, 0, 10), | ||
| "TGraph2D": (100,), | ||
| "TEntryList": ("name", "title"), | ||
| "TEventList": ("name", "title"), | ||
| "TTree": ("name", "title"), | ||
| "TNtuple": ("name", "title", "x:y:z"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these three entries removed from the test cases?
The `TTree` class already deletes the copy constructor and the copy assignment, but users might still be tempted to use the virtual copy constructor or copy assignment provided by `TObject::Clone()` and `TObject::Copy()`. But these implementations also make no sense to the TTree. To avoid user confusion, this commit suggests to override these methods in TTree such that they thow an exception and tell you what to use instead. Prevents reports this one in the future: * https://its.cern.ch/jira/browse/ROOT-9111
The
TTreeclass already deletes the copy constructor and the copy assignment, but users might still be tempted to use the virtual copy constructor or copy assignment provided byTObject::Clone()andTObject::Copy(). But these implementations also make no sense to the TTree.To avoid user confusion, this commit suggests to override these methods in TTree such that they thow an exception and tell you what to use instead.
Prevents reports like this one in the future: