ROOT.std.shared_ptr in Python


ROOT Version: 6.18/00 + Python 3.7.3
Platform: macOS 10.14
Compiler: Apple LLVM version 10.0.1 (clang-1001.0.46.4)


I would like to use std::shared_ptr in PyROOT but only the example I found on the web is Slide 19 of this file.

from ROOT import std, TH1, TH1F
p = std.shared_ptr<TH1>()
if not p : p = TH1F()
p

But unfortunately it does not work on my Mac with the following error.

In [1]: from ROOT import std, TH1, TH1F                                         
In [2]: p = std.shared_ptr<TH1>()                                               
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-65487fb322c1> in <module>
----> 1 p = std.shared_ptr<TH1>()

TypeError: '<' not supported between instances of 'Template' and 'TH1_meta'

So I tried the commands below instead.

In [3]: p = std.shared_ptr(TH1)()                                               
In [4]: p                                                                       
Out[4]: <ROOT.shared_ptr<TH1> object at 0x7fb4e37bb140>
In [5]: p.get()                                                                 
Out[5]: <ROOT.TH1 object at 0x0>

and it looks OK. However, if I assign a TH1F instance to the pointer as demonstrated in the slide, what I get is not a smart pointer of TH1F but just a normal TH1F object.

In [7]: p = TH1F()                                                              
In [8]: p                                                                       
Out[8]: <ROOT.TH1F object at 0x7fb4e9268700>
In [9]: p.get()                                                                 
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-9-b38e1d35dbaf> in <module>
----> 1 p.get()

AttributeError: 'TH1F' object has no attribute 'get'

Question: How do I initialize the pointer?

I tried to initialize with an expected constructor, but it did not work.

In [10]: p = std.shared_ptr(TH1)(TH1F())                                        
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-10-79bb6ebcfc11> in <module>
----> 1 p = std.shared_ptr(TH1)(TH1F())

TypeError: none of the 4 overloaded methods succeeded. Full details:
  shared_ptr<TH1>::shared_ptr<TH1>() =>
    takes at most 0 arguments (1 given)
  shared_ptr<TH1>::shared_ptr<TH1>(const shared_ptr<TH1>& __r) =>
    could not convert argument 1
  shared_ptr<TH1>::shared_ptr<TH1>(shared_ptr<TH1>&& __r) =>
    could not convert argument 1 (this method can not (yet) be called)
  shared_ptr<TH1>::shared_ptr<TH1>(nullptr_t) =>
    could not convert argument 1 (void/unknown arguments can't be set)

std::shared_ptr<TH1>::reset dit not work either.

In [11]: p = std.shared_ptr(TH1)()                                              
In [12]: p.reset(TH1F())                                                        
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-76fb6d96ec93> in <module>
----> 1 p.reset(TH1F())

TypeError: void shared_ptr<TH1>::reset() =>
    takes at most 0 arguments (1 given)

Akira,

not sure what the authors of that document were up to, but yes, that first line is an error (it parses as two inequality comparisons) and the assignment is a reference one, which is why they finally print the object, not the shared pointer.

There is an __assign__, but just like __init__ for the constructor, that won’t work b/c those are templated with the Python name divorced from the C++ name. I’d figure the reset could be instantiated, but I guess that fails, too, without a pre-existing template instantiation, b/c the non-templated reset will usurp them.

Not that either of those would have worked in the end, b/c the call TH1F() would have created a TH1F object, then promptly deleted it after the call was finished, leaving the shared_ptr with a dangling pointer.

The canonical way of creating a shared_ptr, in both C++ and Python, however, is the use of std::make_shared. Unfortunately, support for templated free functions is almost non-existent in PyROOT, and neither does it handle the move argument list.

What is left? Not much: you’re stuck with creating the shared_ptrs in C++ using gInterpreter.ProcessLine, after which they’ll be usable (unless you are on MS Windows due to limitations in ROOT/meta).

Aside, all this, however, incl. patches to ROOT/meta for MS Windows, is resolved in cppyy.

1 Like

Thank you. Yes, ProcessLine works as expected. I will use if for the moment.

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