When does the TObject pointed to by TFile::Get(name) go out of scope?

I want to write a function which returns a TH1D* without getting a dangling pointer. But I am confused about when the histogram read from a TFile would go out of scope.

TH1D* get_histogram() {
    TFile filename ("input_file.root");
    TH1D* histogram_in_function = filename.Get<TH1D>("histogram_name");
 
    return histogram_in_function;
}

int main() {
    TH1D* histogram_in_main = get_histogram();  // will this be a dangling pointer??
 
    delete histogram_in_main;  // do I need this to avoid a memory leak??
}

My question is about the lifetime of the histogram; does the TH1D pointed to by histogram_in_function go out of scope

  1. whenever filename goes out of scope?
  2. at the end of the definition of get_hist()?
  3. not until I call delete? (i.e. the TH1D pointed by histogram_in_function is allocated on the heap)

Clarification: I don’t actually care about when to call delete since I can just use a smart pointer (e.g., unique_ptr<TH1D>) instead of a raw pointer (TH1D*). Another way of asking my question above: Is the object pointed to by histogram_in_function

  1. a local object in get_hist() ?
  2. owned by filename?
  3. an object on the heap?

Thanks is advance for the help!


Please read tips for efficient and successful posting and posting code

ROOT Version: Not Provided
Platform: Not Provided
Compiler: Not Provided


ROOT User’s Guide → Object Ownership

1 Like

The latest documentation for the “Object Ownership” is in the Manual.

1 Like

Thanks for the replies! They were very helpful for understanding ownership a little better.

If I understand correctly, will the following work correctly without giving me a dangling pointer?

TH1D* get_histogram() {
    TFile filename ("input_file.root");
    TH1D* histogram_in_function = filename.Get<TH1D>("histogram_name");
    histogram_in_function->SetDirectory(nullptr); // I added this line
 
    return histogram_in_function;
}

int main() {
    TH1D* histogram_in_main = get_histogram();  // will this be a dangling pointer??
 
    delete histogram_in_main;  
}

Or better yet, with smart pointers:

std::unique_ptr<TH1D> get_histogram() {
    TFile filename ("input_file.root");
    std::unique_ptr<TH1D> histogram_in_function( filename.Get<TH1D>("histogram_name") );
    histogram_in_function->SetDirectory(nullptr); // I added this line
 
    return histogram_in_function;
}

int main() {
    std::unique_ptr<TH1D> histogram_in_main = get_histogram();  // will this be a dangling pointer??
}

I wrote a small program to try out the code in my previous comment and it seems to work.

I also tried out the following program just to be sure and I get an empty TCanvas when I comment out the “h1->SetDirectory(nullptr)” line; if I leave the line in the program, the histogram can be seen on the TCanvas. So it seems, “h1->SetDirectory(nullptr)” does in fact keep the TFile from deleting the histogram when TFile’s lifetime ends.

void ownership_test(TCanvas& c)
{
  TFile f1("input_file.root");
  TH1D* h1 = f1->Get<TH1D>("input_file_histogram");
  
  h1->SetDirectory(nullptr);

  h1->Draw();
}

int main()
{
  TCanvas c;
  ownership_test(c);
  c.Print("ownership_test.pdf");
  return 0; 
}
#include<TCanvas.h>
#include<TFile.h>
#include<TH1D.h>

void ownership_test()
{
   TFile f1("hsimple.root");
   TH1D* h1 = (TH1D*)f1.Get("hpx");
   h1->SetDirectory(nullptr);
   h1->Draw();
}

void ack()
{
   TCanvas c;
   ownership_test();
   c.Print("ownership_test.pdf");
}

I confirm that this macro produces an empty canvas when SetDirectory is commented out.

root [0] .x ack.C++
1 Like

Thanks again for the help!