Object ownership

An object ownership means the permission to delete it. Modern code should use local variables or std::unique_ptr; but some of ROOT’s types are managed differently. To prevent memory leaks and multiple attempts to delete an object, you need to know which objects are owned by ROOT and which are owned by you.

By the end of this page you will know why

void ownership() {
   TFile file("file.root");
   auto hist = new TH1F("hist", "hist", 10, 0., 1.);
   hist->Draw();
}

shows an empty canvas after calling ownership().

Ownership by current directory gDirectory

When a histogram, a TTree or a TEventList is created, it is added by default to the list of objects in the current directory gDirectory. In many cases that is the TFile that was opened most recently.

Example

Changing the directory of a histogram (same applies to trees and event lists):

h->SetDirectory(newDir);

You can remove a histogram from a directory by using SetDirectory(nullptr). Once a histogram is removed from the directory, it will not be deleted when the directory is deleted. Instead, you have to delete the histogram yourself to prevent memory leaks.

Disabling ROOT’s automatic ownership management for histograms

To prevent histograms from being added to the current directory, call the static function

TH1::AddDirectory(kFALSE);

Now you own all histogram objects and you will need to delete them, for instance through the use of std::unique_ptr. You can still set the directory of a histogram by calling SetDirectory() once it has been created.

Example

When you create a TFile object, it becomes the current directory (gDirectory). If you subsequently create a new histogram, this histogram is now owned by the current directory: the histogram is deleted when the TFile object destructed.

In the following example, only an empty canvas is shown because the TH1F histogram is owned by the current directory (gDirectory) corresponding to the TFile object.

void ownership() {
   TFile file("file.root");
   auto hist = new TH1F("hist", "hist", 10, 0., 1.);
   hist->Draw();
   // At the end of the function, `file` is destructed.
   // The destructor `~TFile` deletes `hist`: no histogram is left.
}

In the following example, the canvas shows the histogram because the TH1F histogram is created before the TFile is opened; the TFile does not own it.

void ownership() {
   auto hist = new TH1F("hist", "hist", 10, 0., 1.);
   TFile file("file.root");
   hist->Draw();
}

Finally, this canvas shows the histogram because it is owned by a unique_ptr which lives longer than the function ownership():

std::unique_ptr<TH1> hist;
void ownership() {
   TH1::AddDirectory(false);
   TFile file("file.root");
   hist.reset(new TH1F("hist", "hist", 10, 0., 1.));
   // or, instead of TH1::AddDirectory(false):
   //   hist->SetDirectory(nullptr);
   hist->Draw();
}

Ownership by gROOT

The global gROOT object has several utility collections, for instance of all functions gROOT->GetListOfFunction(), canvases gROOT->GetListOfCanvases(), and files gROOT->GetListOfFiles(). Objects that are members of these collections and are still “alive” during program tear-down are deleted by gROOT. If they get deleted earlier, they de-register themselves from TROOT’s lists (“recursive remove”) to prevent double deletions.

Ownership by creating objects

When an object creates another, the creating object is often the owner of the created one. This will be documented in the function creating the other object.

Example

myHisto->Fit("gaus")

The call of Fit() copies the global TF1 Gaussian function and attaches the copy to the histogram. When the histogram is deleted, the copy is deleted too.