Skip to content

Commit 505df64

Browse files
committed
Update the page on ownership.
1 parent 43a4e09 commit 505df64

1 file changed

Lines changed: 28 additions & 32 deletions

File tree

manual/object_ownership/index.md

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ toc: true
77
toc_sticky: true
88
---
99

10-
An object ownership means the permission to delete it.
11-
Modern code should use local variables or `std::unique_ptr`; but some of ROOT's types are managed differently.
12-
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.
10+
With "owning" an object, we mean being responsible for its lifetime, that is, taking care of deleting it when it's no longer in use.
11+
For new code, we advise to use objects on the stack or smart pointers like `std::unique_ptr`; but some of ROOT's types historically were managed differently.
12+
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 the user.
1313

1414
By the end of this page you will know why
1515
{% highlight C++ %}
@@ -19,12 +19,13 @@ void ownership() {
1919
hist->Draw();
2020
}
2121
{% endhighlight %}
22-
shows an empty canvas after calling `ownership()`.
22+
shows an empty canvas in ROOT 6 after calling `ownership()`.
2323

24-
## Ownership by current directory `gDirectory`
24+
## ROOT 6: Ownership by the current directory `gDirectory`
2525

26-
When a [histogram](https://root.cern/doc/master/group__Hist.html){:target="_blank"}, a {% include ref class="TTree" %} or a {% include ref class="TEventList" %} is created, it is added by default to the list of objects in the current directory [`gDirectory`](https://root.cern/doc/master/classTDirectory.html).
26+
When a [histogram](https://root.cern/doc/master/group__Hist.html){:target="_blank"}, a {% include ref class="TTree" %} or a {% include ref class="TEventList" %} is created in ROOT 6, it registers itself to the current directory [`gDirectory`](https://root.cern/doc/master/classTDirectory.html).
2727
In many cases that is the {% include ref class="TFile" %} that was opened most recently.
28+
This directory now owns the object, and will take care of deleting it.
2829

2930
_**Example**_
3031

@@ -34,26 +35,22 @@ Changing the directory of a histogram (same applies to trees and event lists):
3435
h->SetDirectory(newDir);
3536
{% endhighlight %}
3637

37-
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.
38+
One 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.
3839

39-
### Disabling ROOT's automatic ownership management for histograms
40+
## ROOT 7: Ownership by the user
41+
In ROOT 7, the ownership model will be changed to explicitly hand ownership to the user, because objects such as histograms will not anymore register themselves to the current directory.
42+
Users can still decide to pass the ownership to ROOT directories or ROOT files if they want these to manage an object using `SetDirectory(someDirectory)`.
4043

41-
To prevent histograms from being added to the current directory, call the static function
42-
43-
{% highlight C++ %}
44-
TH1::AddDirectory(kFALSE);
45-
{% endhighlight %}
46-
47-
Now you own all histogram objects and you will need to delete them, for instance through the use of `std::unique_ptr`.
48-
You can still set the directory of a histogram by calling `SetDirectory()` once it has been created.
44+
The ROOT 7 behaviour can be tested already in ROOT 6 using [`DisableObjectAutoRegistration()`](https://root.cern/doc/master/namespaceROOT_1_1Experimental.html#a74fae8f88965b8c79dfbd25bebbce3a4).
45+
Conversely, ROOT 7 can be switched to ROOT 6 behaviour using [`EnableObjectAutoRegistration()`](https://root.cern/doc/master/namespaceROOT_1_1Experimental.html#a15c715c36cf189a6d15ae366da307f23).
4946

5047
_**Example**_
5148

52-
When you create a {% include ref class="TFile" %} object, it becomes the current directory (`gDirectory`).
53-
If you subsequently create a new histogram, this histogram is now owned by the current directory:
54-
the histogram is deleted when the {% include ref class="TFile" %} object destructed.
49+
In ROOT 6, when you create a {% include ref class="TFile" %} object, it becomes the current directory (`gDirectory`).
50+
If you subsequently create a new histogram, this histogram is owned by the current directory:
51+
the histogram is deleted when the {% include ref class="TFile" %} object is destructed.
5552

56-
In the following example, only an empty canvas is shown because the {% include ref class="TH1F" %} histogram is owned by the current directory (`gDirectory`) corresponding to the {% include ref class="TFile" %} object.
53+
In the following example, only an empty canvas is shown because the {% include ref class="TH1F" %} histogram is owned by the {% include ref class="TFile" %} object.
5754
{% highlight C++ %}
5855
void ownership() {
5956
TFile file("file.root");
@@ -64,30 +61,29 @@ void ownership() {
6461
}
6562
{% endhighlight %}
6663

67-
In the following example, the canvas shows the histogram because the {% include ref class="TH1F" %} histogram is created before the {% include ref class="TFile" %} is opened; the `TFile` does not own it.
64+
In ROOT 7 mode, the canvas shows the histogram because it is owned by the `unique_ptr` which lives longer than the function `ownership()`:
6865

6966
{% highlight C++ %}
67+
std::unique_ptr<TH1> hist;
7068
void ownership() {
71-
auto hist = new TH1F("hist", "hist", 10, 0., 1.);
69+
ROOT::Experimental::DisableObjectAutoRegistration(); // Make ROOT 6 behave like ROOT 7
7270
TFile file("file.root");
71+
hist.reset(new TH1F("hist", "hist", 10, 0., 1.));
7372
hist->Draw();
7473
}
7574
{% endhighlight %}
7675

77-
Finally, this canvas shows the histogram because it is owned by a `unique_ptr` which lives longer than the function `ownership()`:
76+
### `TH1::AddDirectory`
77+
78+
To prevent histograms from being added to the current directory, users could in the past call
7879

7980
{% highlight C++ %}
80-
std::unique_ptr<TH1> hist;
81-
void ownership() {
82-
TH1::AddDirectory(false);
83-
TFile file("file.root");
84-
hist.reset(new TH1F("hist", "hist", 10, 0., 1.));
85-
// or, instead of TH1::AddDirectory(false):
86-
// hist->SetDirectory(nullptr);
87-
hist->Draw();
88-
}
81+
TH1::AddDirectory(false);
8982
{% endhighlight %}
9083

84+
We advise to instead use `DisableObjectAutoRegistration()`, because it is thread local, and covers more objects such as TGraph2D, TEfficiency, RooPlot and similar.
85+
For details, see the documentation of [`DisableObjectAutoRegistration()`](https://root.cern/doc/master/namespaceROOT_1_1Experimental.html#a74fae8f88965b8c79dfbd25bebbce3a4).
86+
9187
## Ownership by `gROOT`
9288

9389
The global [`gROOT`](https://root.cern/doc/master/classTROOT.html) object has several utility collections, for instance of all functions `gROOT->GetListOfFunction()`, canvases `gROOT->GetListOfCanvases()`, and files `gROOT->GetListOfFiles()`.

0 commit comments

Comments
 (0)