[C++-sig] Re: Containers for derived classes

Brett Calcott brett.calcott at paradise.net.nz
Fri Aug 8 10:02:38 CEST 2003


>
> Sorry, it still doesn't work:
>
> class C {
>      public:
> void set(A_ptr a) { this->a=a; }
> A_ptr get() { return this->a; }
>      private:
> A_ptr a;
> };
>
> BOOST_PYTHON_MODULE(ptr_test)
> {
>     using namespace boost::python;
>     class_<A, A_ptr>("A", init< int >() )
> .def_readwrite("val", &A::val)
>     ;
>     class_<C>("C", init< >() )
> .def("set", &C::set )
>         .def("get", &C::get )
>     ;
> }
>
> Then, I get in Python:
> >>> from ptr_test import *
> >>> a=A(0)
> >>> c=C()
> >>> c.set(a)
> >>> a1=c.get()
> >>> a
> <ptr_test.A object at 0x008F76C0>
> >>> a1
> <ptr_test.A object at 0x008F68B0>
> >>> a.val
> 0
> >>> a1.val
> 0
> >>> a.val=1
> >>> a1.val
> 1
> >>>
> Hence, a and a1 are not the same Python objects, but the same C++ objects.
> Thus, sub-classing A still doesn't work:
>
> >>> class B(A):
> ...     def __init__(self, i):
> ...             A.__init__(self, i)
> ...             self.name = "foo"
> ...
> >>> b=B(0)
> >>> c.set(b)
> >>> b1=c.get()
> >>> b
> <__main__.B object at 0x008F77B0>
> >>> b1
> <ptr_test.A object at 0x008F6F70>
> >>>


The problem is that for python object 'identity' the PyObject must survive
making it from the python interpreter to C++, and back again. In this case
it doesn't -- it is deleted when you set it, and a new one is constructed
when it returns.

Try this instead:

...
    // class_<A, A_ptr>("A", init< int >() )
    class_<A, boost::noncopyable>("A", init< int >() )
...


This does work. Why? Because Boost.Python uses shared_ptr<A> *internally* to
construct this object, and it does it in a special way so that the PyObject
is referenced as part of the shared_ptr<A> construct -- so it survives the
round trip.

Unfortunately, you can no longer do this (something I'd like to do in a
similar situation.)


class C {
public:
    void set(A_ptr a) { this->a=a; }
    A_ptr get() { return this->a; }
    void create(int i) { a = A_ptr(new A(i)); }
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
private:
    A_ptr a;
};

>>>c.create(1)
>>>c.get()

TypeError: No to_python (by-value) converter found for C++ type: class
boost::s
ared_ptr<class A>

Because this particular shared_ptr is created in C++, it doesn't have the
funky embedded PyObject in it.

So, you get identity, but you lose consistent treatment of shared_ptr<A>. I
haven't figure a way to work around this...

HTH,
Brett











More information about the Cplusplus-sig mailing list