Properly deleting TCanvas any other TObject object


I have a custom class which is a kind of container managing different TObject objects, e.g. histograms, canvases, etc. When I destroy the class object, I want to destory also all objects managed by this class. Therefore, in the destructor I iterate over all objects and call Delete() functien, e.g.:

virtual class::~class() { for (int i = 0; i < arr.size(); ++i) { arr[i]->Delete(); } }

But for objects of TCanvas I receive following message:

which I understand that Delete() for a canvas is not a good idea. What is then the best way to delete this objects? Are threre other kinds of objects which need special treatment? My class can store anything derivating from TObject so anything can be expected.

Why not just the normal C++ delete?

for (int i = 0; i < arr.size(); ++i) {
   if (arr[i]) delete arr[i];

I’ve tried that but from my observation it does not delete the objects at heap. Therefore after many iterations of opening and closing I just run out of memory. I need effective way to release resources.

If you are the ‘owner’ of the objects in the vector of TObject* that have been created with new, then deleting them with the delete operator should work. If you think it is not the case, then it is a bug, and we would be delighted to get a simple reproducer.

Sure, the library managing objects is available on git hub, you can get and compile it in following way:

git clone mkdir SmartFactory/build cd SmartFactory/build cmake .. make

Now you can run an example program

It will create a root file of 1000 TH1F histograms filled with data and write them to root file [quote]example_multi.root[/quote]. Also canvas for each histogram is created and written.

In the next step it will run loop of reading the file and importing all histograms and canvases. It will read all 100 histograms in each loop, and the will delete them by calling destructor for the storage object.

Parameter given to the example is a number of loops, default is 100. While executing the program, please watch memory consumption for this program. On my machine it is rising all the time, which I understand as the memory is not released. Or there is a bug in my code which I missed.

I managed to run your example. The problem is not deleting the elements in your array. The problem is when to read from the file and populate them. With the attached change the example runs with constant memory. Closing and deleting the source file is not necessary if you ensure that will be done by the client. Best practices tells us to delete objects where they have been created.

diff --git a/src/SmartFactory.cxx b/src/SmartFactory.cxx
index e08d1ce..e7df897 100644
--- a/src/SmartFactory.cxx
+++ b/src/SmartFactory.cxx
@@ -107,7 +107,11 @@ SmartFactory::~SmartFactory()
                        delete regobjs[i];
-//     if (source) source->Close();
+   if (source) {
+     source->Close();
+     delete source;
+   }
 void SmartFactory::validate()
@@ -247,8 +251,9 @@ bool SmartFactory::importStructure(TFile* f, bool verbose)
                TObject * o = this->getObject(f, obj->objnames[i].c_str());
                if (o)
-                       this->RegObject(obj->objnames[i].c_str());
-                       if (verbose)
+         //this->RegObject(obj->objnames[i].c_str());
+         this->RegObject(o);
+         if (verbose)
                                std::cout << " [ done ] " << std::endl;

Dear Mato,

your suggestion was very good. Thanks to your comment I could fix more memory leaks in my code.

Thanks and regards,