[C++-sig] shared_ptr object identity

2010-08-15 Thread Erlend Cleveland
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

2010-08-15 Thread Ralf W. Grosse-Kunstleve
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

2010-08-15 Thread Erlend Cleveland
>> 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

2010-08-15 Thread Ralf W. Grosse-Kunstleve
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