Question

I'm using Boost.Python to expose an array of objects within another class:

class Thing {
  int i; // and of course other stuff
};

class Container {
  Thing *things[128];
  int n_things;
}

I'd like to provide to python a read-only list interface to the Things. I have something like this in my boost.python extension source code:

static bp::list EXTget_things(Container &c)
{
  bp::list thing_list;
  for (int i = 0; i < c.n_things; i++) {
    thing_list.append(c.things[i]);
  }
  return thing_list;
}

I also have the (unusual?) constraint that I can't copy the Thing objects. They don't have a working copy constructor, and I can't really change that. I'd like to just return a python list containing the addresses of the original objects, and correspondingly ensure that python doesn't free the originals when it frees the list.

How can I do that? (Or can it be done?) I recognize it could cause lifetime problems if the Container goes out of scope in python, but some other python code still tries to use the param_list (since it has pointers into the Collection object), but I'm willing to work with that restriction.

Was it helpful?

Solution

One approach is to expose both classes:

class_<Thing>("thing")
    .def_readwrite("i", &Thing::i)
;

class_<Container>("container")
    .def_readwrite("n_things", &Container::n_things)
;

and then create a method that returns a reference to the Thing:

Thing& get_thing(Container& c, size_t index)
{
    return *c.things[index];
}

finally, you should expose this function:

def("get_thing", get_thing, return_value_policy<reference_existing_object>());

and than you can iterate over it:

c = mylib.container()
for i in xrange(c.n_things):
    thing = get_thing(c, i)
    thing.i = <INT_VALUE>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top