Last active
March 10, 2018 10:24
-
-
Save blapid/69cba9f58abf38ecb84a0d3c1a241fef to your computer and use it in GitHub Desktop.
Playing around with ownerships and lists in pybind11
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <list> | |
#include <memory> | |
#include <pybind11/pybind11.h> | |
#include <pybind11/stl.h> | |
struct B; | |
struct A { | |
A() {}; | |
~A() { | |
printf("~A()\n"); | |
if (!b_list.empty()) { | |
printf("b_list not empty!\n"); | |
} | |
}; | |
void register_b(B *b) { | |
b_list.push_back(b); | |
}; | |
void unregister_b(B *b) { | |
auto removed = std::remove(b_list.begin(), b_list.end(), b); | |
b_list.erase(removed, b_list.end()); | |
}; | |
std::list<B *> b_list; | |
}; | |
struct B { | |
B(A& a) : m_a(a) { | |
m_a.register_b(this); | |
}; | |
~B() { | |
printf("~B()\n"); | |
m_a.unregister_b(this); | |
}; | |
A& m_a; | |
}; | |
/* | |
* Enforce the destruction order by wrapping A in a shared_ptr, and | |
* B in a unique_ptr to itself and a shared_ptr to A. | |
* This means that each B item in the list which python receives from | |
* "get_b_list" holds a shared_ptr to the A that was used in it's creation. | |
* If python deletes it's A before all of the B's, the shared_ptr refcount | |
* will still be positive and A will not be deleted until the last of the | |
* B's are deleted by python. | |
*/ | |
struct AHolder : public std::shared_ptr<A> { | |
AHolder() : std::shared_ptr<A>(new A()) {} | |
}; | |
//Note: The order of inheritance is important! We want B to get destructed before AHolder! | |
struct BHolder : public AHolder, std::unique_ptr<B> { | |
BHolder(AHolder& a) : AHolder(a), std::unique_ptr<B>(new B(*a)) {} | |
}; | |
namespace py = pybind11; | |
PYBIND11_MODULE(example, m) { | |
m.doc() = "pybind11 example plugin"; // optional module docstring | |
py::class_<BHolder>(m, "B"); | |
py::class_<AHolder>(m, "A") | |
.def(py::init<>()) | |
.def("get_b_list", [](AHolder _this) -> std::list<BHolder> { | |
std::list<BHolder> b_list; | |
b_list.push_back({_this}); | |
b_list.push_back({_this}); | |
return b_list; | |
}, py::return_value_policy::move); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment