Storing a raw C pointer member

The script below demonstrates the problem scenario:
I have a class (here struct B) that contains a member (_a) that is a raw pointer (to a different user class, struct A). After some setup I need to grab that raw pointer, call a method of the class that updates that member, and then use the old raw pointer. Perhaps this can be done using BindObject and friends, but I don’t quite see how.

import ROOT as R
cpp_code = """
struct A {
int _i = 7;
};

struct B {
A* _a;
B( A* a) : _a( a ) {}
void f() { delete _a; _a = new(A); }
};
"""
R.gInterpreter.ProcessLine( cpp_code );
pA = R.A()
pA._i = 3
pB = R.B( pA )
# the usage scenario starts here:
# - somehow note who is pB._a so this "A" object can be queried as needed later
# - call pB.f()
# - query the old "A" object
old_a = pB._a
R.gInterpreter.ProcessLine( 'A* old_p = pA;' )
print('It is really the old A, pA:',old_a._i)
pB.f()
print('But now, it is a new A:',old_a._i)

Hi @harelamnon,
I think it’s a bug that B.f() deletes the old A if you want to still be able to access it afterwards.

Assuming the code is as above but without the delete _a;, it seems to work as expected in ROOT v6.22. It’s possible that the switch to new PyROOT fixed this particular issue.

Could you check whether ROOT v6.22 solves your problem? It’s available e.g. from lxplus, or as a conda package (see https://root.cern/install).

Cheers,
Enrico

As pointed out by Enrico, the deletion of the A object in the C++ side can be problematic, because it is done without PyROOT knowing about it. This means old_a will become a Python proxy that points to a C++ object that has been deleted.

Also, in the second ProcessLine of the code you posted you are using a C++ identifier that does not exist, since pA only exists as a variable in Python.

If I understood correctly what you want to do, you can write:

old_a = pB._a   # old_a now points to the A C++ object in pB
new_a = R.A()
pB.SetNewA(new_a) # this updates the internal A* of pB
# from this point you can also use the old A object via old_a
1 Like

Thanks guys!
Clearly, my simplified code failed to make the point. I think this, even simpler, code will show the issue without the distractions you pointed out.

cpp_code = """
struct A {
int _i = 7;
};

struct B {
A* _a;
B( A* a) : _a( a ) {}
void f() { _a = new(A); }
};
"""
R.gInterpreter.ProcessLine( cpp_code );
pA = R.A()
pA._i = 3
pB = R.B( pA )
# the usage scenario starts here:
# - somehow note who is pB._a so this "A" object can be queried as needed later
# - call pB.f()
# - query the old "A" object
old_a = pB._a
print('It is really the old A, pA:',old_a._i)
pB.f()
print('But now, it is a new A:',old_a._i)

This prints:
It is really the old A, pA: 3
But now, it is a new A: 7

So “old_a” track the C++ pointer, rather than the object being pointed to…

Hi,

I see the issue now, thank you for clarifying.

I tried to run your example with old PyROOT (<=6.20) and new PyROOT(>=6.22), and the new one does not have the behaviour you report anymore. Instead, the new PyROOT prints:

It is really the old A, pA: 3
But now, it is a new A: 3

So the C++ object pointed to by old_a (which is the same as pA, since pA and old_a are bound to the same Python proxy) is not affected by the internal change in pB.

Therefore, I suggest that you try a newer version of ROOT to have this issue fixed.

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