Inheritance w/ memory_policy as boost shared_ptr

Asked by John Gash

I've come across a problem in my understanding of pybindgen or a problem with pybindgen's handing of boost::shared_ptr<> and inheritance. I running on RH, gcc, and pybindgen's trunk as of Aug 1.

Thanks in advance for your assistance.

Code and script to create bindings are at the end of the message (gz sample project available).

----------------------------------------------------
Description:

The example includes two classes a Parent and a Child (which extends Parent). Under the default
memory management policy, the code compiles correctly and can be easily tested. When
changing the memory policy to support boost's shared_ptr<>, compiling the generated binding code
will not compile.

A couple of observations of the generated code w/ boost memory policy:

1. Code: self_obj_before = reinterpret_cast< PyExampleParent* >(m_pyself)->obj;
   Should this not be a cast to the boost::shared_ptr<Parent> or (m_pyself)->obj.get()?

2. Code: PyExampleChild__PythonHelper *helper_class = dynamic_cast<PyExampleChild__PythonHelper*> (self->obj);
   As obj is a boost::shared_ptr<Child>, should not the call dynamic_cast<>(self->obj.get())?

3. The Child data structure (PyExampleChild) contains a handle (obj) to the Child instance it
   manages as the root class Parent. This is okay, except for cases where the generated code calls
   the helper class or casts. Code:

      // original: (helper_class == NULL)? (self->obj->hello()) : (self->obj->Example::Child::hello());
      /* modified */ (helper_class == NULL)? (self->obj->hello()) : (helper_class->hello());

      // error: invalid conversion from 'Example::Parent*' to 'Example::Child*'
      self_obj_before = reinterpret_cast< PyExampleChild* >(m_pyself)->obj;

4. Code: ((PyExampleChild__PythonHelper*) self->obj)->set_pyobj((PyObject *)self);
   Since self->obj is a boost::shared_ptr<>, should be self->obj.get()

----------------------------------------------------
Code (.cpp not shown):

namespace Example {
  class Parent {
    public:
      Parent();
      virtual void hello();
  };

  class Child : public Parent {
    public:
      Child();
      virtual void hello();
  };
}

----------------------------------------------------
bindings.py:

import sys
from pybindgen import Parameter, Module, FileCodeSink
from pybindgen import cppclass

def gen_shared():
    mod = Module('Simple')
    ns = mod.add_cpp_namespace("Example")
    ns.add_include('"inherit.hpp"')

    # Note this creates code that does not compile (see README).
    parentC = ns.add_class('Parent', allow_subclassing=True, memory_policy=cppclass.BoostSharedPtr('::Example::Parent'))

    # Works as expected
    #parentC = ns.add_class('Parent', allow_subclassing=True)

    parentC.add_constructor([])
    parentC.add_method('hello', None, [], is_virtual=True)

    childC = ns.add_class('Child', allow_subclassing=True, parent=parentC)
    childC.add_constructor([])
    childC.add_method('hello', None, [], is_virtual=True)

    out_file=open("./gen_inherit.cpp",'w')
    mod.generate(FileCodeSink(out_file) )

if __name__ == '__main__':
    gen_shared()

Question information

Language:
English Edit question
Status:
Solved
For:
PyBindGen Edit question
Assignee:
No assignee Edit question
Solved by:
Gustavo Carneiro
Solved:
Last query:
Last reply:
Revision history for this message
Gustavo Carneiro (gjc) said :
#1

It doesn't sound like you're doing anything wrong, more likely a code path in pybindgen not well tested. I'll take a look. First thing I'll do is to add this test case to tests/boost.

Revision history for this message
Gustavo Carneiro (gjc) said :
#2

I see that this is simply incomplete work to support boost::shared_ptr. The problem is the allow_subclassing setting, which enables subclassing in Python user code. PyBindGen is not yet supporting the combination of boost::shared_ptr and allow_subclassing=True. It needs more work to support it.

 Note, if you only need to binding two classes where one is base class of another, you don't need allow_subclassing=True.

Revision history for this message
John Gash (gash1) said :
#3

Thanks for taking a look.

The example is a simplification of what is being attempted; a more involved inheritance graph (P<-A, A<-B, B<-C, B<-D, ...) is modeled s.t. other methods accept the base class (e.g,. fn(boost::shared_ptr<P> value)) .

allow_subclassing removal - Without inheritance, abstractions like fn() would not be possible.

Revision history for this message
Best Gustavo Carneiro (gjc) said :
#4

I'm not sure you understand what allow_subclassing is for. allow_subclassing is to enable this:

  import myextension

  class MySubclass(myextension.BaseClass):
         ...

If you need, you can have class A deriving from class B, both wrapped by your extension, even with allow_subclassing=False. allow_subclassing only means "allow python code to subclass my extension types", it does not influence the ability to wrap two classes where one inherits from the other.

That been said, it is a pity that pybindgen does not support boost::shared_ptr with allow_subclassing, but it requires a few more hours of coding to get it working.

Revision history for this message
John Gash (gash1) said :
#5

Thanks Gustavo Carneiro, that solved my question.