Std::unique_ptr to TTree in TFile


ROOT Version: root/6.12.06
Platform: Red Hat Enterprise Linux Server release 7.6 (Maipo)
Compiler: gcc/6.2.0


Is there a correct way to create a std::unique_ptr to a TTree in a TFile?

I am used to doing:

TFile* file = new TFile("name.root", "READ");                                  
TTree* tree = (TTree*) file->Get("name");

but would like to start using std::unique_ptr, so I tried:

auto file = std::unique_ptr<TFile> {TFile::Open("name.root", "READ")};
auto tree = std::unique_ptr<TTree> {file->Get("name")}; // this does not work!

This does not compile with ACLiC. The first error message is:

error: no matching constructor for initialization of 'std::unique_ptr<TTree>'

Is there a correct way to do this? Is there anything I should be aware of (any “gotchas” in terms of ROOT’s memory management)? Also, please let me know if there is a better way to create a std::unique_ptr to a TFile (the first line in my example).

Thanks

Hi,
to make it compile, you just need to cast the TObject* returned by TFile::Get to a TTree*.
Or you can use the TFile::GetObject variant to get a TTree* directly.

But you will have to be very careful with the lifetimes of those file and tree pointers: TFile owns the objects extracted from it, so:

  • if file goes out of scope before tree, it will delete the TTree object, then tree's destructor will also delete the TTree object (like a good unique_ptr does) and you will get a crash
  • if tree goes out of scope before file, the TTree destructor will inform its TFile and deregister from it, so everything is fine

Another solution is to use unique_ptr for the TFile (guarantees no TFile leaks) and use a raw TTree* pointer for the TTree, with the modern C++ meaning of non-owning pointer, leaving it up to the TFile destructor to delete the TTree object.

Hope this is more clarifying than it is confusing :sweat_smile:
Cheers,
Enrico

Hi Enrico,

Thanks for your help! I think I will follow your suggestion of creating a raw pointer to the TTree. In that case I will simply do:

auto file = std::unique_ptr<TFile> {TFile::Open("name.root", "READ")};
auto tree = (TTree*) file->Get("name");

Out of curiosity though, I would like to learn how to create the std::unique_ptr to the TTree in my example. Would you please provide the correct syntax? I tried:

auto tree = (std::unique_ptr<TTree>) file->Get("evtTree");

which yields this error:

error: no matching conversion for C-style cast from 'TObject *' to 'std::unique_ptr<TTree>'

Thanks

Hi,
it’s

auto tree = std::unique_ptr<TTree>(static_cast<TTree*>(file->Get("evtTree")))

(you can substitute static_cast with a C-style cast if you prefer).

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.