[C++-sig] Properly copying wrapped classes

Jim Bosch jbosch at astro.princeton.edu
Sun Jun 3 17:25:38 CEST 2012


On 05/31/2012 08:49 PM, Jay Riley wrote:
> I'm having a problem with some python objects derived in python. I have
> a Clone method that's supposed to make a full copy of these python
> inherited objects, but it isn't working. The problem is my wrapper
> class' PyObject* self isn't getting copied, so when I use
> call_method<>(self, "method name"), self will never point to the copied
> instance. Here's a brief example showing the issue
>

<snip>

>
> Sorry about the length, just want to make sure I got everything relevant
> in. When I run this code, it prints:
>
> Python Clone
> Python Side Test. ID: 1
> Python Side Test. ID: 1
> Original ID 1
> Clone ID 1
>
> this is wrong because Clone ID should be 2 (inspecting the object
> confirms it is 2). Like I said I'm pretty sure the problem is that the
> wrapper class' copy constructor only makes a copy of the PyObject* self,
> not a full copy. This is how every reference doc I saw was doing class
> wrapping, but isn't this wrong? Should we be making a full copy of the
> PyObject*? How would I go about doing that, or otherwise modifying my
> classes to get the behaviour I expect.
>

There are a couple of things here that probably need to be addressed:

  - Be wary of relying on copy-constructor side effects to demonstrate 
whether something is working; the compiler is allowed to elide copy 
constructors under many conditions, which might result in misleading 
results.  That said, I don't think that's what's causing your problem 
here (or at least not all of it).

  - Your implementations of __copy__ and __deepcopy__ won't work with 
polymorphic wrapper classes, because they construct a BaseClass instance 
and tell Boost.Python to wrap it by managing the new reference.  That 
necessarily makes a Python object that holds a BaseClass object, not one 
that holds a BaseClassWrap object.  If you want to get a BaseClassWrap 
Python object, you want to pass it by value to Boost.Python; that should 
invoke the BaseClassWrap copy constructor and pass it a new PyObject* to 
manage (so it doesn't have to copy the PyObject* itself).

I think that just means you can remove the "managingPyObject" function, 
and instead use:

object result(extract<const Copyable &>(copyable)());


HTH

Jim


More information about the Cplusplus-sig mailing list