Support ownership transfer for unique_ptr<T> (move-only holders) from Python to C++ (and back) · Issue #1132 · pybind/pybind11 (original) (raw)

I had reviewed some of the prior questions on GitHub, StackOverflow, etc, and found that accepting a unique_ptr<T> from Python is not presently possible (ref: one of the GitHub issues).

I think that this can be done, and have made a (rough, but not too rough) prototype of doing so that I believe is generally comprehensive for most of the simple edge cases.

branch | head commit (as of writing)

Demo Usage

Code sampled from this pseudo-test case.

class Base { public: Base(int value) : value_(value) {} virtual ~Base() {} virtual int value() const { return value_; } private: int value_{}; };

// Trampoline class. class PyBase : public py::trampoline { public: typedef py::trampoline TBase; using TBase::TBase; int value() const override { PYBIND11_OVERLOAD(int, Base, value); } };

// Make a terminal function. void terminal_func(unique_ptr ptr) { cout << "Value: " << ptr->value() << endl; ptr.reset(); // This will destroy the instance. cout << "Destroyed in C++" << endl; }

// Declare class. py::class_<Base, PyBase>(m, "Base") .def(py::init()) .def("value", &Base::value); m.def("terminal_func", &terminal_func);

// Extend and use it in some Python code. py::exec(R"( class PyExtBase(m.Base): def init(self, value): m.Base.init(self, value) def del(self): print("PyExtBase.del") def value(self): return 10 * m.Base.value(self)

m.terminal_func([m.Base(20)]) )");

Should print something like:

Value: 200
PyExtBase.__del__
Destroyed in C++

Functionality Overview

Caveats / Limitations

Followup

I would really like to have this feature, so please do let me know if this seems like viable feature option. I am more than happy to submit a PR and go through the review process if so desired (which would be a much more polished, properly unit-tested version of the prototype branch).

\cc @jagerman