diff --git a/example/example5.cpp b/example/example5.cpp index 91e0b4fd..34c7abe1 100644 --- a/example/example5.cpp +++ b/example/example5.cpp @@ -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 { + Payload p; + + return [p]() { + /* p should be cleaned up when the returned function is garbage collected */ + }; + }); } diff --git a/example/example5.py b/example/example5.py index 5aaaae7f..b7e3cd36 100755 --- a/example/example5.py +++ b/example/example5.py @@ -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() diff --git a/example/example5.ref b/example/example5.ref index 51c1b05c..372cbe81 100644 --- a/example/example5.ref +++ b/example/example5.ref @@ -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 diff --git a/include/pybind/pybind.h b/include/pybind/pybind.h index 9e707c12..9ca1929f 100644 --- a/include/pybind/pybind.h +++ b/include/pybind/pybind.h @@ -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(f), std::tuple(std::forward(extra)...) }; + if (!std::is_trivially_destructible::value) + m_entry->free = [](void *ptr) { delete (capture *) ptr; }; + typedef arg_value_caster cast_in; typedef return_value_caster 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;