Smart pointers in root

Hello,

I am trying to use a smart pointer with TH1::Clone(), but I am getting always an error that looks like this:

g++ -O2 -Wall -fPIC -g -ansi -pthread -std=c++1y -m64 -I/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/x86_64/root/6.10.04-x86_64-slc6-gcc62-opt/include -I. -Iinclude -c src/DMttAnalysis.cxx -o lib/DMttAnalysis.o
In file included from /cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/x86_64/Gcc/gcc620_x86_64_slc6/6.2.0/x86_64-slc6/include/c++/6.2.0/bits/shared_ptr.h:52:0,
from /cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/x86_64/Gcc/gcc620_x86_64_slc6/6.2.0/x86_64-slc6/include/c++/6.2.0/memory:82,
from /cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/x86_64/root/6.10.04-x86_64-slc6-gcc62-opt/include/TFitResultPtr.h:29,
from /cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/x86_64/root/6.10.04-x86_64-slc6-gcc62-opt/include/TH1.h:42,
from include/Analysis.h:12,
from include/DMttAnalysis.h:5,
from src/DMttAnalysis.cxx:1:
/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/x86_64/Gcc/gcc620_x86_64_slc6/6.2.0/x86_64-slc6/include/c++/6.2.0/bits/shared_ptr_base.h: In instantiation of ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Tp1*) [with _Tp1 = TObject; _Tp = TH1F; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]’:
/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/x86_64/Gcc/gcc620_x86_64_slc6/6.2.0/x86_64-slc6/include/c++/6.2.0/bits/shared_ptr.h:117:32: required from ‘std::shared_ptr<_Tp>::shared_ptr(_Tp1*) [with _Tp1 = TObject; _Tp = TH1F]’
src/DMttAnalysis.cxx:273:56: required from here
/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase/x86_64/Gcc/gcc620_x86_64_slc6/6.2.0/x86_64-slc6/include/c++/6.2.0/bits/shared_ptr_base.h:885:39: error: invalid conversion from ‘TObject*’ to ‘TH1F*’ [-fpermissive]
: _M_ptr(__p), _M_refcount(__p)

Followed by a bunch of other endless incomprehensible lines. What I am doing is something like this:

shared_ptr h_full=0;
shared_ptr h_pd=0;

h_pd = (shared_ptr)h_full->Clone(hname.c_str());

I have tried using dynamic_cast, static_cast, dynamic_pointer_cast, static_pointer_cast and some other functions with identical result. I haven’t had any problems when using other TH1 functions, this only comes out with cloning.

Can anybody help me with this?

Thanks,
Andrea

Hi,
the error message says you are passing a TObject* to construct a shared_ptr<TH1F>.
You need to convert it:

auto h_rawptr =  static_cast<TH1F*>(h_full->Clone(hname.c_str()));
auto h_pd = std::make_shared<TH1F>(h_rawptr);

Hope this helps,
Enrico

Hi,
make_shared is used to perfectly forward constructor arguments to the corresponding constructor. That is, you could write something like this to construct a histogram “h” with 100 bins from 0 to 100:

auto sp = make_shared<TH1F>("h", "h", 100, 0, 100);

You cannot use it the way Enrico showed it because there is no TH1F constructor taking a TH1F* as argument (and if there was such a thing, you wouln’t want to use it here). Use shared_ptr<TH1F>(h_rawptr) instead.

Also, I would always avoid TH1F* and use TH1* instead (except when calling the constructor). Why limit to TH1F? To summarize:

auto h_pd = shared_ptr<TH1>(static_cast<TH1*>(h_full->Clone(hname.c_str())));
// or
shared_ptr<TH1> h_pd;
h_pd.reset(static_cast<TH1*>(h_full->Clone(hname.c_str())));

Another point: do you really really need a shared_ptr? Wouldn’t a unique_ptr suffice?
(or no smart pointer at all since ROOT might manage the histogram on its own, depending on TH1::AddDirectory).

1 Like

…as @behrenhoff says :slight_smile:

Thank you @behrenhoff and @eguiraud for your answers. I tried both solutions but unfortunately I keep getting the same error. I am using the smart pointers because I was getting a memory leak that was not easy to track, and I need shared_ptr because I use the histograms in several functions of the code, and it was not possible with the unique_ptr. But neither the reset nor the make_shared or the shared_ptr conversion worked.

Hi,
I suggest you carefully inspect the error messages you get to pinpoint the exact line and the exact cause of the compilation failure.
What happens in your original error message is that TH1F::Clone returns a TObject* (see the docs) and you need to cast it to TH1F* to construct a std::shared_ptr<TH1F>.

As a reference, this short snippet compiles correctly:

#include <TH1F.h>

int main() {
   TH1F h("h", "h", 100, 0., 10.);
   auto h_clone = static_cast<TH1F*>(h.Clone("h_clone"));
   std::shared_ptr<TH1F> clone_ptr(h_clone);
   
   return 0;
}

Cheers,
Enrico

Strage, probably your error is elsewhere. The line you have quoted works. Try it:

root [0] auto h_full = new TH1F("h","h",100,0,100);
root [1] string hname("newname");
root [2] auto h_pd = shared_ptr<TH1>(static_cast<TH1*>(h_full->Clone(hname.c_str())));

No error.

Functions just USING a histogram and not dealing with ownership should NOT have smart pointers as arguments! No ownership semantics -> Suggest using T* or T&. See the c++ core guidelines: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-smartptrparam

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.