Support keep_alive where nurse may be None

For example keep_alive<0,1>() should work where the return value may sometimes be None. At present a "Could not allocate weak reference!" exception is thrown.
Update documentation to clarify behaviour of keep_alive when nurse is None or does not support weak references.
This commit is contained in:
Glen Walker 2016-08-16 17:50:43 +12:00
parent e357ed3cc8
commit f45bb585c3
5 changed files with 42 additions and 7 deletions

View File

@ -663,10 +663,13 @@ In addition to the above return value policies, further `call policies` can be
specified to indicate dependencies between parameters. There is currently just specified to indicate dependencies between parameters. There is currently just
one policy named ``keep_alive<Nurse, Patient>``, which indicates that the one policy named ``keep_alive<Nurse, Patient>``, which indicates that the
argument with index ``Patient`` should be kept alive at least until the argument with index ``Patient`` should be kept alive at least until the
argument with index ``Nurse`` is freed by the garbage collector; argument argument with index ``Nurse`` is freed by the garbage collector, as long as the
indices start at one, while zero refers to the return value. For methods, index nurse object supports weak references (pybind11 extension classes all support
one refers to the implicit ``this`` pointer, while regular arguments begin at weak references). If the nurse object does not support weak references and is
index two. Arbitrarily many call policies can be specified. not None an appropriate exception will be thrown. Argument indices start at
one, while zero refers to the return value. For methods, index one refers to
the implicit ``this`` pointer, while regular arguments begin at index two.
Arbitrarily many call policies can be specified.
Consider the following example: the binding code for a list append operation Consider the following example: the binding code for a list append operation
that ties the lifetime of the newly added element to the underlying container that ties the lifetime of the newly added element to the underlying container

View File

@ -22,6 +22,7 @@ public:
~Parent() { std::cout << "Releasing parent." << std::endl; } ~Parent() { std::cout << "Releasing parent." << std::endl; }
void addChild(Child *) { } void addChild(Child *) { }
Child *returnChild() { return new Child(); } Child *returnChild() { return new Child(); }
Child *returnNullChild() { return nullptr; }
}; };
void init_ex_keep_alive(py::module &m) { void init_ex_keep_alive(py::module &m) {
@ -30,7 +31,9 @@ void init_ex_keep_alive(py::module &m) {
.def("addChild", &Parent::addChild) .def("addChild", &Parent::addChild)
.def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>()) .def("addChildKeepAlive", &Parent::addChild, py::keep_alive<1, 2>())
.def("returnChild", &Parent::returnChild) .def("returnChild", &Parent::returnChild)
.def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>()); .def("returnChildKeepAlive", &Parent::returnChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveChild", &Parent::returnNullChild, py::keep_alive<1, 0>())
.def("returnNullChildKeepAliveParent", &Parent::returnNullChild, py::keep_alive<0, 1>());
py::class_<Child>(m, "Child") py::class_<Child>(m, "Child")
.def(py::init<>()); .def(py::init<>());

View File

@ -31,6 +31,7 @@ if True:
gc.collect() gc.collect()
print(p) print(p)
p = None p = None
gc.collect() gc.collect()
print("") print("")
@ -41,6 +42,26 @@ if True:
print(p) print(p)
p = None p = None
gc.collect()
print("")
if True:
p = Parent()
p.returnNullChildKeepAliveChild()
gc.collect()
print(p)
p = None
gc.collect()
print("")
if True:
p = Parent()
p.returnNullChildKeepAliveParent()
gc.collect()
print(p)
p = None
gc.collect() gc.collect()
print("") print("")
print("Terminating..") print("Terminating..")

View File

@ -22,4 +22,12 @@ Allocating child.
Releasing parent. Releasing parent.
Releasing child. Releasing child.
Allocating parent.
<example.Parent object at 0x10eb726c0>
Releasing parent.
Allocating parent.
<example.Parent object at 0x10eb726c0>
Releasing parent.
Terminating.. Terminating..

View File

@ -1098,8 +1098,8 @@ inline void keep_alive_impl(handle nurse, handle patient) {
if (!nurse || !patient) if (!nurse || !patient)
pybind11_fail("Could not activate keep_alive!"); pybind11_fail("Could not activate keep_alive!");
if (patient.ptr() == Py_None) if (patient.ptr() == Py_None || nurse.ptr() == Py_None)
return; /* Nothing to keep alive */ return; /* Nothing to keep alive or nothing to be kept alive by */
cpp_function disable_lifesupport( cpp_function disable_lifesupport(
[patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); }); [patient](handle weakref) { patient.dec_ref(); weakref.dec_ref(); });