views:

255

answers:

1

Trying to set up a dependency in C++ with a parent-child relationship. The parent contains the child and the child has a weak pointer to the parent.

I would also like to be able to derive from the parent in Python. However, when I do this, I get a weak pointer error connecting up this parent-child relationship.

C++ code:

#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

using namespace boost;
using namespace boost::python;

struct Child;

struct Parent : public enable_shared_from_this<Parent>
{
    void initialize();
    shared_ptr<Child> m_child;
};

struct Child: public enable_shared_from_this<Child>
{
    void setParent(shared_ptr<Parent> ptr);
    weak_ptr<Parent> m_parent;
};

void Parent::initialize()
{
    shared_ptr<Child> ptr(new Child);
    m_child = ptr;

    m_child->setParent(shared_from_this());
}

void Child::setParent(shared_ptr<Parent> ptr)
{
    m_parent = ptr;
}

static PyObject* create(PyObject* object)
{
    PyObject* instance = PyObject_CallObject(object, NULL);

    Parent* parent = extract<Parent*>(instance);
    parent->initialize();

    return instance;
}

Python binding:

BOOST_PYTHON_MODULE(test_module)
{
    class_<Parent>("Parent");

    def("create", &create);
}

Python code:

from test_module import *

class Test(Parent):
    def __init__(self):
        Parent.__init__(self)

n = create(Test)

Error:

Traceback (most recent call last):
  File "main.py", line 8, in <module>
    n = create(Test)
RuntimeError: tr1::bad_weak_ptr

If I try and convert the extracted pointer to Parent into a shared_ptr, I get a free() invalid pointer error in Python.

Is there a way of getting round this problem or should I give up using weak pointers with Boost Python?

+1  A: 

I played with the code without the python stuff.

This reproduced the problem:

Parent* p(new Parent);
p->initialize();

The problem is nothing is holding on to the shared_ptr object. This fixes it:

boost::shared_ptr<Parent> p(new Parent);
p->initialize();

Boost.Python FAQ : "When a shared_ptr is converted from Python, the shared_ptr actually manages a reference to the containing Python object. When a shared_ptr is converted back to Python, the library checks to see if it's one of those "Python object managers" and if so just returns the original Python object"

The Parent* needs to be stored in a shared_ptr somehow. I haven't figured out how yet.

Parent* parent = boost::python::extract<Parent*>(instance);
Eddy Pronk