[C++-sig] shared_ptr object identity
Hi all, I've been bashing my head against a wall for the past couple of days trying to figure this out. It's frustrating because it seems like it should be such a simple thing. I've also read through every archived message I can find relating to this topic, but just can't seem to pull it all together. Here is a minimal example showing what I'm trying to do: --- C++: #include class Bar {}; typedef boost::shared_ptr BarPtr; BarPtr mFooInstance = BarPtr(new Bar()); BarPtr getBar() { return mBarInstance; } -- C++ / Python binding: #include using namespace boost::python; BOOST_PYTHON_MODULE(Foo) { class_("Bar", no_init); def("getBar", &getBar); register_ptr_to_python(); } -- Python: import Foo bar1 = Foo.getBar() bar2 = Foo.getBar() assert bar1 == bar2# Assert fails due to bar1 and bar2 having separate python objects All I would like to achieve is for bar1 and bar2 to point to the same python object, in the case where the object was created on the C++ side, such that I can add python attributes to such instances and have this state preserved. Note that I am using a global mFooInstance for simplicity, but in reality such object will be held as members or in containers. Thanks in advance for any help! ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] shared_ptr object identity
Hi Erland, > I've been bashing my head against a wall for the past couple of days > trying to figure this out. It's frustrating because it seems like it > should be such a simple thing. I cannot be so simple if you think of the C++ side as being unaware of the Python layer. Each time the C++ function is called Boost.Python has to create a new Python object. I believe it is very difficult or maybe even impossible to reliably return the same Python object like you expect. > BarPtr getBar() > { > return mBarInstance; > } I think your example can be made to work like this (untested): In the file with the Python bindings: boost::python::object getBar_wrapper() { static boost::python::object result = getBar(); return result; } With: def("getBar", getBar_wrapper); But I've not tested it. > Note that I am using a global mFooInstance for > simplicity, but in reality such object will be held as members That still seems doable, via a wrapper object. > or in containers. If you have pure C++ containers in mind I think it is possible only via virtual functions that you override in a wrapper object. But maybe the best solution is something else, without requiring object identity: - Add all data attributes to the C++ object (and use .def_readonly() or .def_readwrite()). Then the state of the object is preserved naturally. - Inject additional Python methods as described in the Boost.Python tutorial: http://www.boost.org/doc/libs/1_43_0/libs/python/doc/tutorial/doc/html/python/techniques.html#python.extending_wrapped_objects_in_python Ralf ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] shared_ptr object identity
>> I've been bashing my head against a wall for the past couple of days > >> trying to figure this out. It's frustrating because it seems like it >> should be such a simple thing. > > I cannot be so simple if you think of the C++ side as being unaware of > the Python layer. Each time the C++ function is called Boost.Python has > to create a new Python object. I believe it is very difficult or maybe > even impossible to reliably return the same Python object like you expect. Well that's somewhat comforting to know :) >> Note that I am using a global mFooInstance for >> simplicity, but in reality such object will be held as members > > That still seems doable, via a wrapper object. > So I would wrap member functions returning the shared_ptr, and store a persistent reference to the python object, returning its shared_ptr instead? > - Add all data attributes to the C++ object (and use .def_readonly() or > .def_readwrite()). > Then the state of the object is preserved naturally. > > - Inject additional Python methods as described in the Boost.Python tutorial: > > http://www.boost.org/doc/libs/1_43_0/libs/python/doc/tutorial/doc/html/python/techniques.html#python.extending_wrapped_objects_in_python None of these methods would allow me to extend the individual instances dynamically with attributes in python, correct? I suppose I could create some python code to wrap attributes and map to them from an ID on the object, but I can't imagine that would be terribly generic or concise. I stumbled upon this post in my search - http://mail.python.org/pipermail/cplusplus-sig/2006-March/010169.html. It talks about swapping out the shared_ptr with one that manages the Python object instead, so that presumably, subsequent usage of the shared_ptr will allow Python to know about the object. Unfortunately it doesn't seem to fit with my scenario, and is possibly more relevant to embedded python, but isn't there some way to write a custom to_python_converter to allow me to inject that code whenever a shared_ptr is to be converted to python? Earl ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig
Re: [C++-sig] shared_ptr object identity
Hi Earl, > So I would wrap member functions returning the shared_ptr, and store a > persistent reference to the python object, returning its shared_ptr > instead? Yes. > > - Add all data attributes to the C++ object (and use .def_readonly() or > > .def_readwrite()). > > Then the state of the object is preserved naturally. > > > > - Inject additional Python methods as described in the Boost.Python tutorial: > > > > >http://www.boost.org/doc/libs/1_43_0/libs/python/doc/tutorial/doc/html/python> >/techniques.html#python.extending_wrapped_objects_in_python > > None of these methods would allow me to extend the individual > instances dynamically with attributes in python, correct? Yes. Do I understand correctly that you want to use the object essentially like a dictionary, just with obj.key instead of obj["key"]? I consider this bad practice, since it isn't obvious to readers of your code. Did you consider adding a boost::python::object member to your C++ object? That would solve all your problems I think and it would be obvious. If you need to keep your C++ code independent of Python, you could work with boost::any. > but isn't there some way to write a custom > to_python_converter to allow me to inject that code whenever a > shared_ptr is to be converted to python? I think you could make this work, but you'd have to maintain a registry. I'd look for a more conventional solution first. Ralf ___ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig