How can I make a TCanvas own all the graphical objects painted on it (TH1, TGraph, TF1, TLegend etc.) so that all of them are automatically deleted when the canvas is deleted?
Thanks.
have you tried to use SetBit(kCanDelete); ?
Yes, I tried. I put together a simple script with some children of graphical classes which just prints out a string when constructor/destructor is called. I create some of these objects, set the bit, draw them and then delete the canvas, and I see that nothing from the destructor is printed. The script is attached, and this is the output on my machine:
test.c (726 Bytes)
When I run your script (ROOT 6 on Mac). I get:
root [0] .L test.c
root [1] Draw()
TH1FC
TGraphC
TF1C
~TH1FC
~TGraphC
~TF1C
root [2]
It seems the destructors are called …
With ROOT 5 try to use Aclic.
In ROOT 5 you will need to precompile (i.e. use ACLiC) your macro as your classes inherit from compiled classes.
Compilig with Aclic it works as expected, and also with gcc. I was mislead by cint, sorry for the noise and thanks for the help.
Edit: I see now your example run on Mac. I run on Linux 64 bit, Root version is 5.34.30.
Compiling with Aclic still gives problems when drawing a clone of a graph. With the attached script I get:
[quote]
$ root
root [0] .L test.c+
Info in TUnixSystem::ACLiC: creating shared library /tmp/test_c.so
Error in : TGraphC inherits from TObject but does not have its own ClassDef
Error in : TH1FC inherits from TObject but does not have its own ClassDef
Error in : TF1C inherits from TObject but does not have its own ClassDef
root [1] Draw()
TH1FC
TGraphC
TF1C
~TH1FC
~TF1C
root [2][/quote]
test.c (934 Bytes)
Any hint about the issue with the clone graphs?
It works for me (ROOT6)
root [0] .L test-5.c
root [1] Draw()
TH1FC
TGraphC
TF1C
~TH1FC
~TF1C
Sorry Olivier, but to me your output does not look as if it were working. I see one “TGraphC” which should come from the explicit call to new TGraphC; I guess there’s no “TGraphC” output for the creation of the clone because the clone is created with the streamer and not with the constructor. So everything looks fine for what concerns graph creation.
I would expect that a single “~TGraphC” would be outputted due to the deletion of the clone graph (it is fine that g is not deleted since it is now drawn). But I see none of these “~TGraphC” messages, so I guess that the clone is not destroyed.
I tried to run the example with valgrind: compiling the attached example (changing void Draw() to int main()) with gcc and Root 5.34.30 and running memcheck I get many memory leaks coming from Clone at line 47 of test.c. I’m not 100% sure whether these leaks are due to a missing destruction of the clone object or not (many of them seems related to Cint) , but at least this looks like it:
Am I right or am I completely missing some point? Thanks.
Sorry I just had a quick look and as I did not see the errors messages you re ported in your post I thought it was ok.
you had :
Error in <TGraphC>: TGraphC inherits from TObject but does not have its own ClassDef
and I don’t.
Ah, I see. Sorry for not having polished my example for those errors, but I thought that they were not relevant for this issue so I didn’t take care of them. It’s understandable that you have been mislead by them.
The “Clone” method (and some another ones) uses the “Streamer” facility. You do not provide the “Streamer” for your derived class, so the “cloned” object will be broken (the “Streamer” of the base class will be used).
It’s a pity that ROOT 6 does not issue the warning as does ROOT 5.
Hi Coyote, could you elaborate a bit the concept of “broken”? Does this just imply the printout of the warnings (at least in this case) or does it causes also the missed deletion of the cloned object?
I produced the simple example because I am investigating some memory leaks in my program which seems to be due to clones of TGraph (the original Root class), so I still suspect that something is causing leaks even with clones standard Root classes. Thanks.
I think, even though “g” is a “TGraphC*”, in case of your original “test.c” macro, “g->Clone()” will return a “TGraph*” and NOT a “TGraphC*” (i.e. only the base class will be cloned).
Try the attached “test.c” (I cannot guarantee that everything will work, of course).
test.c (1.05 KB)
Hi Coyote, you are right. When adding a streamer to TGraphC I can see the call to ~TGraphC. So it seems that the clone object is correctly deleted when kCanDelete is set. Thank you very much.
As a side note, I still get lots of leaks according to valgrind. The most puzzling one is one that seems related to the memory allocation for the clone graph. In the tet program attached to this message I create a clone, set kCanDelete, draw it and then delete the canvas. According to your test, the clone’s destructor should be correctly called, but memcheck gives me this:
The leak above appears also if I don’t set kCanDelete and delete the clone manually. The leak report is full of various kind of leaks related to Root, and I wonder if they are real or if I am misinterpreting the valgrind report. If they are real, is there anyone taking care of these issues (at least for Root 6?). Thanks.
test-graph.c (226 Bytes)
Do you use [url=https://root-forum.cern.ch/t/segmentation-fault-depending-on-linux-distribution/18020/6 valgrind “suppressions”[/url]?
I didn’t know about valgrind suppressions, thanks for the tip. With the test program attached to my previous post (test-graph.c) and launching valgrind as:
valgrind --tool=memcheck --leak-check=full --suppressions=root-config --etcdir
/valgrind-root.supp
I get a much smaller leak report (in attachment). There is still a large portion of leaked memory which is marked as still reachable and not suppressed. I wonder whether this memory has to be considered as an additional part of the unavoidable leaks covered in valgrind-root.supp or this is a real leak.
valgrind.txt (32.6 KB)
Well, you could try without “–leak-check=full”. <img src="/uploads/default/original/2X/8/84c2fe9464a4066c00e1bd5978e913e7869cbb07.gif" width=“22” height=“16” alt=":-"" title=“Whistle”/>