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
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…
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.
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
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).
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
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
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
[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]
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]