Stephen
Stephen

Reputation: 2823

Can boost::python pass ownership of an object to a python callback function?

I am currently passing a C++ pointer to a python callback function with the boost::python::call function. This works fine, but if I don't subsequently delete the pointer in the C++ code, I introduce a memory leak.

I would like to pass the pointer to the callback and have python's garbage collector handle the lifetime of the object. Right now, if I want to save the object passed to the callback, I have to do a deep copy.

I have seen here that this sort of thing is possible with return values of wrapped C++ function with return_value_policy<manage_new_object>. Is it possible to do something similar with the arguments to boost::python::call?

Upvotes: 4

Views: 584

Answers (1)

Barry
Barry

Reputation: 302643

The way manage_new_object works is by being a metafunction class that converts an argument into a converted result that the caller must take responsibility for. With the normal call policies, it's used under the hood. We just have to use that metafunction class explicitly ourselves:

struct Foo {
    X* x = ...;

    void give_up_x(py::object callback) {
        py::manage_new_object::apply<X*>::type wrapper;
        callback(py::handle<>{wrapper(x)});
    }
};

You need py::handle<> since wrapper gives you back a PyObject* instead of a py::object. If you want to be more direct, you can skip some of the intermediate type instantiations and just use:

void give_up_x(py::object callback) {
    callback(py::handle<>{py::detail::make_owning_holder::execute(x)});
}

I came upon the above through guess-and-check. It looks like it works at least?

Upvotes: 4

Related Questions