install a cleanup handler for nontrivial lambda closures

This commit is contained in:
Wenzel Jakob 2015-10-13 17:37:25 +02:00
parent 28f98aa298
commit 19208fe9a4
4 changed files with 42 additions and 1 deletions

View File

@ -72,4 +72,29 @@ void init_ex5(py::module &m) {
m.def("test_callback2", &test_callback2);
m.def("test_callback3", &test_callback3);
m.def("test_callback4", &test_callback4);
/* Test cleanup of lambda closure */
struct Payload {
Payload() {
std::cout << "Payload constructor" << std::endl;
}
~Payload() {
std::cout << "Payload destructor" << std::endl;
}
Payload(const Payload &) {
std::cout << "Payload copy constructor" << std::endl;
}
Payload(Payload &&) {
std::cout << "Payload move constructor" << std::endl;
}
};
m.def("test_cleanup", []() -> std::function<void(void)> {
Payload p;
return [p]() {
/* p should be cleaned up when the returned function is garbage collected */
};
});
}

View File

@ -24,6 +24,7 @@ from example import test_callback1
from example import test_callback2
from example import test_callback3
from example import test_callback4
from example import test_cleanup
def func1():
print('Callback function 1 called!')
@ -38,3 +39,5 @@ print(test_callback2(func2))
test_callback3(lambda i: i + 1)
f = test_callback4()
print("func(43) = %i" % f(43))
test_cleanup()

View File

@ -12,3 +12,9 @@ Callback function 2 called : Hello, x, True, 5
5
func(43) = 44
func(43) = 44
Payload constructor
Payload copy constructor
Payload move constructor
Payload destructor
Payload destructor
Payload destructor

View File

@ -69,6 +69,7 @@ private:
void *data = nullptr;
bool is_constructor = false, is_method = false;
short keywords = 0;
void (*free) (void *ptr) = nullptr;
return_value_policy policy = return_value_policy::automatic;
std::string signature;
PyObject *class_ = nullptr;
@ -242,6 +243,9 @@ private:
m_entry = new function_entry();
m_entry->data = new capture { std::forward<Func>(f), std::tuple<Extra...>(std::forward<Extra>(extra)...) };
if (!std::is_trivially_destructible<Func>::value)
m_entry->free = [](void *ptr) { delete (capture *) ptr; };
typedef arg_value_caster<Arg...> cast_in;
typedef return_value_caster<Return> cast_out;
@ -333,7 +337,10 @@ private:
static void destruct(function_entry *entry) {
while (entry) {
delete entry->def;
operator delete(entry->data);
if (entry->free)
entry->free(entry->data);
else
operator delete(entry->data);
function_entry *next = entry->next;
delete entry;
entry = next;