CERN ROOT's Objects Ownership and C++11 Smart Pointers

1.9k Views Asked by At

I am trying to understand how smart pointers are expected to live with ROOT object ownership scheme. I didn't have to go very far. Look at this

#include <iostream>
#include <memory>
#include "TH1F.h"
#include "TFile.h"

int main()
{
  TFile f("out.root", "recreate");
  f.cd();
  std::unique_ptr<TH1F> h {new TH1F("h", "h", 100, -5, 5)};
  h->FillRandom("gaus", 10000);
  h->Write();
  f.Close();

  return 0;
}

The histogram which is handled by a unique pointer was owned by the current gDirectory. Since I politely closed the file before I exit my program the histogram was destroyed by ROOT memory management guy. Now at the end of main() my pointer goes out of scope and its resource needs to be freed, but it has already been freed!

I haven't found any resources on how ROOT object ownership/memory management is expected to live with C++11 smart pointers.

My question to you, do you use smart pointers in code where ROOT objects management is turned on? Do you use C++11 smart pointers in your HENP experiment?

3

There are 3 best solutions below

1
On

If you use TH1::AddDirectory(false), you will manage the histograms and then there will be no problem using smart pointers.

4
On

Well, I would guess to make unique_ptr and ROOT happily married, you have to use custom deleter.

In custom deleter you have to check if histogram still alive and delete it, otherwise make it no-op

Something like (in pseudocode)

auto deleter = [](TH1F* p) { key = FindKey(p->Name); if (key) delete p };

std::unique_ptr<TH1F, decltype(deleter)> h{new TH1F("h", "h", 100, -5, 5), deleter};

more complex schemes could be devised...

0
On

If you are using std::unique_ptr, you really want it to be the sole owner of the object. You can turn off ROOT's object ownership for one histogram with h->SetDirectory:

#include <iostream>
#include <memory>
#include "TH1F.h"
#include "TFile.h"

int main()
{
  TFile f("out.root", "recreate");
  f.cd();
  std::unique_ptr<TH1F> h {new TH1F("h", "h", 100, -5, 5)};
  h->SetDirectory(0);
  h->FillRandom("gaus", 10000);
  h->Write();
  f.Close();

  return 0;
}

This way you still have ROOT's object ownership for all other histograms, but you can own this one yourself.