Write object (of an user defined class) to TFile

Dear people,
I have a class which inherits from TNamed. Let’s call it PPlot.
It contains in addition (as protected members):

  1. A pointer to a TObjArray.
  2. A pointer to a TCanvas.

In the constructor, I define the TCanvas (using new) and some histograms which are immediately added to the TObjArray and to the TCanvas using Draw command.
If I print the TCanvas to a png file for instance, it does work as expected, but if I try to write the whole object ( the PPlot object) to a TFile, the TObjArray and the TCanvas are NULL when I try to read them back from disk. The memory reserved for the the pointers in the constructor of the PPlot object is not stored in the file.

I have been following ROOT’s user manual and I cannot figure out the problem.
A dictionary is created for the class using the following statement in the LinkDef.hh file:
#pragma link C++ class PPlot+;
In the definition of the class, the pointers to TCanvas and TObjArray have the //-> comment on their right.

I am sure that I am missing something, but I don’t figure out.
Could anybody please tell me what is wrong?
How can I save the TObjArray and the TCanvas defined in my class to a TFile?



Did you generate the dictionary for your class, compiled it and loaded it? Did you initialize the pointer in the default constructor (the ‘->’ requires this initialization)? How do you retrieve the object from the file? How do you store them?


Dear Philippe,
Thanks for the reply, but I partially solved my problems, although I didn’t really realize what was wrong at the beginning. Now my objects can be created, stored and read back from disk. No problem.

However, I have another issue now which I don’t understand.
To simplify the problem, let’s forget about the class.
I hava a macro, which create a TCanvas, histograms, labels, etc.
If I use the macro in a precompiled program and I print the canvas to a file it works, but if I run the macro
interactively (from ROOT’s cint), the canvas appears but the histograms on it are not displayed!
I have written this little macro which reproduces the problem. Just type ‘.x test.C’ from root.

test.C (2.76 KB)

  1. comment out four lines which contain “SetFillStyle(4000);” (they break your macro, I don’t know why but it seems something is broken/unprotected in ROOT) -> “4000” is valid for “TPad” only, see: http://root.cern.ch/root/html/TAttFill.html
  2. also replace two appearances of “NULL” with “((TH2F *)0)”

wow… thanks!
It is incredible how much time and effort one can spend in things like this.
Sometimes the errors are perversely hidden. Only the “SetFillStyle(4000);” is causing the problem.
What is the problem in using NULL in the initialization of my “vector<TH2F *>”?

And other thing: Every time I use a TPaveText I have to define its attributes to remove the border line, the shadow, the fill color, etc. Isn’t there a way to define these attributes by default in the style?

“NULL” is an integer number, “((TH2F )0)" is a pointer -> any decent compiler will issue an error: "invalid conversion from ‘int’ to ‘TH2F’” if you try to “mix” them.

You can say “gStyle->SetFillStyle(…)”, “gStyle->SetFillColor(…)”, and so on, but then these settings will automatically be used by many other classes (graphics, histograms) and I don’t know of any way to restrict them to “TPaveText” objects, see: http://root.cern.ch/root/html/TStyle.html
You could try to use the following trick.
Create a single empty/dummy “TPaveText” object and set all your preferred attributes for it.
Then use that object when you create any other “TPaveText” object, using either the “copy constructor” or the “assignment operator”: http://root.cern.ch/root/html/TPaveText.html
They will then “inherit” all attributes from the “common source” object.
(Of course, you can also write a simple c++ routine which does what you want and then simply call that routine every time you create a “TPaveText” object. Instead of a routine you could also write a simple “function-like preprocessor macro”.)

Ok, I got your point, but my compiler (gcc 4.1.2) never complains about the NULL initialization.
Anyway it’s better to do it in your way if it is more standard and/or appropriate.

About the TPaveText attributes, thanks for the tricks. I think I will use the C++ routine since I already have a collection of this kind of functions for the style.


[quote=“Pepe Le Pew”]“NULL” is an integer number, “((TH2F )0)" is a pointer -> any decent compiler will issue an error: "invalid conversion from ‘int’ to ‘TH2F’” if you try to “mix” them.

That’s not quite true. In fact, as far as I know, doing TH2F* test = 0 is completely equivalent to TH2F* test = (TH2F *)0
You just made explicit the implicit conversion that your compiler does anyway. Which compiler does complain for this kind of syntax?
Anyway even if you want to use the explicit conversion it would be probably better to use static_cast rather than the C-style conversion even if the syntax is more verbose.

You may need to change “vector<TH2F *>” into “std::vector<TH2F *>” (two places in the “test.C”), then … [...]$ `root-config --cxx --cflags` -c test.C In file included from /usr/include/c++/4.4/vector:65, from test.C:1: /usr/include/c++/4.4/bits/stl_vector.h: In member function ‘void std::vector<_Tp, _Alloc>::_M_initialize_dispatch(_Integer, _Integer, std::__true_type) [with _Integer = int, _Tp = TH2F*, _Alloc = std::allocator<TH2F*>]’: /usr/include/c++/4.4/bits/stl_vector.h:303: instantiated from ‘std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const _Alloc&) [with _InputIterator = int, _Tp = TH2F*, _Alloc = std::allocator<TH2F*>]’ test.C:18: instantiated from here /usr/include/c++/4.4/bits/stl_vector.h:991: error: invalid conversion from ‘int’ to ‘TH2F*’ /usr/include/c++/4.4/bits/stl_vector.h:991: error: initializing argument 2 of ‘void std::vector<_Tp, _Alloc>::_M_fill_initialize(size_t, const _Tp&) [with _Tp = TH2F*, _Alloc = std::allocator<TH2F*>]’
For the moment I don’t see any difference between “((TH2F *)0)” and “static_cast<TH2F *>(0)”.