class has pure virtual methods Error

Asked by Gregor Burger

Hi,

i get this error:
./genbindings.py:13: UserWarning: exception CodeGenerationError('Node cannot be constructed (class has pure virtual methods)',) in wrapper public: virtual NodeConnection * ISimulation::createConnection (Node * source, std::string source_port, Node * sink, std::string sink_port);

when i want to wrap the methode like this:
sim.add_method('createConnection', retval('NodeConnection*', caller_owns_return=True), [
  param('Node *', 'source', transfer_ownership=False),
  param('std::string', 'source_port'),
  param('Node *', 'sink', transfer_ownership=False),
  param('std::string', 'sink_port')], is_pure_virtual=True)

when i remove the is_pure_virtual from createConnection or change transfer_ownership to
True it works. But that is no what i want. Both Node and ISimulation have pure virtual methods.
This works in other situations.

The backtrace is:

  File "/usr/lib/python2.6/site-packages/pybindgen/utils.py", line 128, in call_with_error_handling
    return callback(*args, **kwargs)
  File "/usr/lib/python2.6/site-packages/pybindgen/cppmethod.py", line 912, in generate
    decl_post_modifiers=decl_post_modifiers)
  File "/usr/lib/python2.6/site-packages/pybindgen/typehandlers/base.py", line 612, in generate
    param.convert_c_to_python(self)
  File "/usr/lib/python2.6/site-packages/pybindgen/cppclass_typehandlers.py", line 666, in convert_c_to_python
    write_create_new_wrapper()
  File "/usr/lib/python2.6/site-packages/pybindgen/cppclass_typehandlers.py", line 581, in write_create_new_wrapper
    '*'+self.value)
  File "/usr/lib/python2.6/site-packages/pybindgen/cppclass.py", line 941, in write_create_instance
    construct_type_name = self.get_construct_name()
  File "/usr/lib/python2.6/site-packages/pybindgen/cppclass.py", line 956, in get_construct_name
    raise CodeGenerationError("%s cannot be constructed (class has pure virtual methods)" % self.full_name)
  File "/usr/lib/python2.6/site-packages/pybindgen/utils.py", line 128, in call_with_error_handling
    return callback(*args, **kwargs)
  File "/usr/lib/python2.6/site-packages/pybindgen/cppmethod.py", line 912, in generate
    decl_post_modifiers=decl_post_modifiers)
  File "/usr/lib/python2.6/site-packages/pybindgen/typehandlers/base.py", line 612, in generate
    param.convert_c_to_python(self)
  File "/usr/lib/python2.6/site-packages/pybindgen/cppclass_typehandlers.py", line 666, in convert_c_to_python
    write_create_new_wrapper()
  File "/usr/lib/python2.6/site-packages/pybindgen/cppclass_typehandlers.py", line 581, in write_create_new_wrapper
    '*'+self.value)
  File "/usr/lib/python2.6/site-packages/pybindgen/cppclass.py", line 941, in write_create_instance
    construct_type_name = self.get_construct_name()
  File "/usr/lib/python2.6/site-packages/pybindgen/cppclass.py", line 956, in get_construct_name
    raise CodeGenerationError("%s cannot be constructed (class has pure virtual methods)" % self.full_name)

thanks

Question information

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

Using raw object pointers without reference counting is always tricky. In addition, you have allow_subclassing=True in the class. Therefore, pybindgen needs to create wrappers in both directions, Python-to-C and C-to-Python. It is the C-to-Python wrapper that is causing problems.

The code for the C-to-Python wrapper pybindgen wants to generate (with transfer_ownership=False) is:

NodeConnection * ISimulation__Helper::createConnection (Node * source, std::string source_port, Node * sink, std::string sink_port)
{
[...]
   PyNode *pynode;
   pynode = <<<create the python wrapper>>>;
   pynode->obj = *source; <<<since transfer_ownership=False, we need to copy the object, otherwise it's not safe>>>
[...]
   <<<< call the python method >>>>>
 [...]
}

Presumably things could be made to work: the python wrapper takes a shared pointer to the original object, not a copy, and after the call the pointer is made NULL. The risk is that, after the call any python code that keeps a reference to the object and calls a method on it will crash because the object is NULL.

This solution is not implemented, and I don't really like it (reference counting is better), but, well, it's an imperfect world, sometimes imperfect solutions are needed.

To unblock your situation, I see only two possible solutions: 1) disable subclassing support in the Node class (allow_subclassing=False), or 2) add reference counting to your C++ APIs.

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

Erm.. instead of:

    pynode->obj = *source;

I meant to say:

    pynode->obj = new Node (*source);

Can you help with this problem?

Provide an answer of your own, or ask Gregor Burger for more information if necessary.

To post a message you must log in.