Boost::shared_ptr and TFile

Hi rooters,

a quick question I am trying to learn about smart pointers and container classes.
In particular I am trying to fit a set of functions to a set of graphs stored in a root file I have the following code which is not compiling

int n=10;
char Tfilename[50];

vector< boost::shared_ptr < TGraphErrors > > gr_ptr(n);
vector< boost::shared_ptr < TF1 > > my_func_ptr;

for(int i=0;i<n;i++){ 
    sprintf(Tfilename, "gr%d", i);
    gr_ptr[i] = (TGraphErrors*)f.Get(Tfilename);
}

the error I am getting is along the lines

classes/Analyse_data.cpp:74: error: no match for ‘operator=’ in ‘gr_ptr. std::vector<_Tp, _Alloc>::operator[] [with _Tp = boost::shared_ptr<TGraphErrors>, _Alloc = std::allocator<boost::shared_ptr<TGraphErrors> >](((long unsigned int)exp_i)) = make_shared<TGraphErrors>’ /usr/local/include/include/boost/smart_ptr/shared_ptr.hpp:309: note: candidates are: boost::shared_ptr<T>& boost::shared_ptr<T>::operator=(const boost::shared_ptr<T>&) [with T = TGraphErrors]

If there are more conventional c++ ways to solve this problem I would be interested basically I would like to deal with this without having to worry about memory management. I had previously had a working solution using an array of pointers and I thought the transition to vectors and shared_ptr would be straight forward but apparently not…

thanks for your help

Mark

This is not a ROOT-related question. Please, read here boost.org/doc/libs/1_52_0/li … ed_ptr.htm
about shared_ptr, in particular, look at ctors/assignment operators this class has, also, notice the ‘explicit’ keyword. In short - use ‘reset’ member function.

Also, please, read about object ownership in ROOT - and check, how it will work together with smart pointers.

Hi,

Are you sure you want to make shared_ptr’s from the TGraphErrors*? If they come from a file their lifetime is managed by the owning TFile and you don’t need to manage their memory (by e.g. deleting them). Basically “you don’t need to delete what you didn’t create”, so a weak_ptr might be a better fit.

As for your immediate problem, the issue is that in

gr_ptr[i] = (TGraphErrors*)f.Get(Tfilename);

you try to implicitly create a boost::shared_ptr from a TGraphErrors* which is not allowed. Instead you have to create a shared_ptr from it with an explicit call

#include <boost/make_shared.hpp>
// ...
gr_ptr[i] = boost::make_shared<TGraphErrors>(f.Get(Tfilename));

In general if you need to store pointers in containers and want their lifetime to be managed by the container Boost provides some abstraction for that (http://www.boost.org/doc/libs/1_52_0/libs/ptr_container/doc/ptr_vector.html). But like I wrote, I don’t think you should manage the memory for these objects at all here.

And since by using Boost you are clearly writing C++ code, stop using char[] and switch over to std::string. That would also allow you to use nice functions like boost::lexical_cast to get rid of the nasty sprintf (you should at least have used snprintf to begin with).

If an object comes from a ROOT file, you need to know what happens with this object when you close this file.

For example, by default, TH[123], TGraph2D, TTree objects will automatically be deleted from memory, when you close the file.
Note that, you can change their behaviour using the “SetDirectory” method (e.g. after you retrieve a histogram from a file, use “MyHistogram->SetDirectory(gROOT);”).

This is different, however, for objects like a TGraph (and some another classes, but I don’t know any comprehensive list of them) -> if you retrieve it from a file, it will stay in memory after you close the file (I assume this is also the case for a TGraphErrors).

Hi Will,

thank you for your clarification, I wasn’t aware of this. If TGraphErrors* aren’t owned by the containing TFile one should of course delete them or store them in some smart pointer which manages their memory (e.g. a scoped_ptr/unique_ptr or shared_ptr).

Oftentimes I wish ROOT interfaces would use some clear ownership abstraction for all the pointers floating around in the API. I am pretty sure this is one issue that gives a lot of people (especially beginners) tons of unneeded headaches. I really love that cling will soon allow me to write C++ in code interfacing with ROOT, but even more I would have loved to see ROOT clean up its dated and inconsistent API to be more C++. I am already looking forward to root-7 :wink:

Thanks everyone for the useful suggestions I have attempted to follow honks suggestion I am still however getting errors. With the following substitution to the previous example

gr_ptr[exp_i] = boost::make_shared<TGraphErrors>(boost::ref(f.Get(Tfilename)));

I get the error

test.cpp: In function ‘int main()’:
test.cpp:22: error: invalid initialization of non-const reference of type ‘TObject*&’ from a temporary of type ‘TObject*’
/usr/local/include/include/boost/ref.hpp:64: error: in passing argument 1 of ‘const boost::reference_wrapper<T> boost::ref(T&) [with T = TObject*]’

if I remove the boost::ref (which I thought was a necessary work around in order to call make_shared) I get the following error

/usr/local/include/include/boost/smart_ptr/make_shared.hpp: In function ‘boost::shared_ptr<X> boost::make_shared(const A1&) [with T = TGraphErrors, A1 = TObject*]’:
test.cpp:22:   instantiated from here
/usr/local/include/include/boost/smart_ptr/make_shared.hpp:660: error: invalid conversion from ‘TObject* const’ to ‘Int_t’
/usr/local/include/include/boost/smart_ptr/make_shared.hpp:660: error:   initializing argument 1 of ‘TGraphErrors::TGraphErrors(Int_t)’

I have attached a working example and root file reproducing the errors
thanks again for your help

Mark
graphs.root (269 KB)
test.cpp (594 Bytes)

Instead of “f.Get(Tfilename)” try “((TGraphErrors)(f.Get(Tfilename)))”.

[quote=“emza0114”]Thanks everyone for the useful suggestions I have attempted to follow honks suggestion I am still however getting errors. With the following substitution to the previous example
[/quote]

What about calling ‘reset’ I’ve suggested?

Thanks Will both solutions worked…

tpochep it wasnt clear to me how to implement your suggestion could you give a short example?

cheers

Mark

[quote=“emza0114”]Thanks Will both solutions worked…

tpochep it wasnt clear to me how to implement your suggestion could you give a short example?

cheers

Mark[/quote]

gr_ptr[exp_i] .reset(… your expression obtaining pointer here …);

Note that “boost::reset” takes a POINTER argument (not a “reference” argument, as “boost::make_shared” and “boost::ref” do).
So, you need to use “(gr_ptr[exp_i]).reset( ((TGraphErrors*)(f.Get(Tfilename))) );”.

[quote=“Wile E. Coyote”]Note that “boost::reset” takes a POINTER argument (not a “reference” argument, as “boost::make_shared” and “boost::ref” do).
So, you need to use “(gr_ptr[exp_i]).reset( ((TGraphErrors*)(f.Get(Tfilename))) );”.[/quote]

He does not need all these nice parenthesis.

gr_ptr[exp_i].reset((TGraphErrors*)f.Get(Tfilename));