From 6e213c9ca04e5f9b1959db5524544bed5fd8f684 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Tue, 24 Nov 2015 23:05:58 +0100 Subject: [PATCH] improved shared pointer support (fixes #14) --- docs/advanced.rst | 8 + example/example8.cpp | 36 +++++ example/example8.py | 14 ++ example/example8.ref | 288 +++++++++++++++++++----------------- include/pybind11/cast.h | 13 ++ include/pybind11/pybind11.h | 18 +++ 6 files changed, 240 insertions(+), 137 deletions(-) diff --git a/docs/advanced.rst b/docs/advanced.rst index 692e6cbf7..5433f2073 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -457,6 +457,14 @@ be declared at the top level before any binding code: demonstrates how to work with custom reference-counting holder types in more detail. +.. warning:: + + To ensure correct reference counting among Python and C++, the use of + ``std::shared_ptr`` as a holder type requires that ``T`` inherits from + ``std::enable_shared_from_this`` (see cppreference_ for details). + +.. _cppreference: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this + .. _custom_constructors: Custom constructors diff --git a/example/example8.cpp b/example/example8.cpp index cb9491658..17ca98c90 100644 --- a/example/example8.cpp +++ b/example/example8.cpp @@ -31,14 +31,36 @@ private: int value; }; +class MyObject2 : public std::enable_shared_from_this { +public: + MyObject2(int value) : value(value) { + std::cout << toString() << " constructor" << std::endl; + } + + std::string toString() const { + return "MyObject2[" + std::to_string(value) + "]"; + } + + virtual ~MyObject2() { + std::cout << toString() << " destructor" << std::endl; + } + +private: + int value; +}; + /// Make pybind aware of the ref-counted wrapper type PYBIND11_DECLARE_HOLDER_TYPE(T, ref); +PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr); Object *make_object_1() { return new MyObject(1); } ref make_object_2() { return new MyObject(2); } MyObject *make_myobject_4() { return new MyObject(4); } ref make_myobject_5() { return new MyObject(5); } +MyObject2 *make_myobject2_1() { return new MyObject2(1); } +std::shared_ptr make_myobject2_2() { return std::make_shared(2); } + void print_object_1(const Object *obj) { std::cout << obj->toString() << std::endl; } void print_object_2(ref obj) { std::cout << obj->toString() << std::endl; } void print_object_3(const ref &obj) { std::cout << obj->toString() << std::endl; } @@ -49,6 +71,11 @@ void print_myobject_2(ref obj) { std::cout << obj->toString() << std:: void print_myobject_3(const ref &obj) { std::cout << obj->toString() << std::endl; } void print_myobject_4(const ref *obj) { std::cout << (*obj)->toString() << std::endl; } +void print_myobject2_1(const MyObject2 *obj) { std::cout << obj->toString() << std::endl; } +void print_myobject2_2(std::shared_ptr obj) { std::cout << obj->toString() << std::endl; } +void print_myobject2_3(const std::shared_ptr &obj) { std::cout << obj->toString() << std::endl; } +void print_myobject2_4(const std::shared_ptr *obj) { std::cout << (*obj)->toString() << std::endl; } + void init_ex8(py::module &m) { py::class_> obj(m, "Object"); obj.def("getRefCount", &Object::getRefCount); @@ -69,5 +96,14 @@ void init_ex8(py::module &m) { m.def("print_myobject_3", &print_myobject_3); m.def("print_myobject_4", &print_myobject_4); + py::class_>(m, "MyObject2") + .def(py::init()); + m.def("make_myobject2_1", &make_myobject2_1); + m.def("make_myobject2_2", &make_myobject2_2); + m.def("print_myobject2_1", &print_myobject2_1); + m.def("print_myobject2_2", &print_myobject2_2); + m.def("print_myobject2_3", &print_myobject2_3); + m.def("print_myobject2_4", &print_myobject2_4); + py::implicitly_convertible(); } diff --git a/example/example8.py b/example/example8.py index e918a77fa..339e008ec 100755 --- a/example/example8.py +++ b/example/example8.py @@ -8,6 +8,8 @@ from example import make_object_1 from example import make_object_2 from example import make_myobject_4 from example import make_myobject_5 +from example import make_myobject2_1 +from example import make_myobject2_2 from example import print_object_1 from example import print_object_2 from example import print_object_3 @@ -16,6 +18,10 @@ from example import print_myobject_1 from example import print_myobject_2 from example import print_myobject_3 from example import print_myobject_4 +from example import print_myobject2_1 +from example import print_myobject2_2 +from example import print_myobject2_3 +from example import print_myobject2_4 for o in [make_object_1(), make_object_2(), MyObject(3)]: print("Reference count = %i" % o.getRefCount()) @@ -35,3 +41,11 @@ for o in [make_myobject_4(), make_myobject_5(), MyObject(6), 7]: print_myobject_2(o) print_myobject_3(o) print_myobject_4(o) + + +for o in [make_myobject2_1(), make_myobject2_2()]: + print(o) + print_myobject2_1(o) + print_myobject2_2(o) + print_myobject2_3(o) + print_myobject2_4(o) diff --git a/example/example8.ref b/example/example8.ref index 87577a915..26f42e3f1 100644 --- a/example/example8.ref +++ b/example/example8.ref @@ -1,261 +1,275 @@ MyObject[1] constructor -Initialized ref from pointer 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 MyObject[2] constructor -Initialized ref from pointer 0x7ff7d9742150 -Initialized ref from pointer 0x7ff7d9742150 -Destructing ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Initialized ref from pointer 0x7ffdb2c167a0 +Destructing ref 0x7ffdb2c167a0 MyObject[3] constructor -Initialized ref from pointer 0x7ff7d9741800 +Initialized ref from pointer 0x7ffdb2c17420 Reference count = 1 MyObject[1] Created empty ref -Initialized ref from pointer 0x7ff7d9742750 -Move-assigning ref 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 +Move-assigning ref 0x7ffdb2c16a50 Destructing ref 0x0 -Initialized ref from ref 0x7ff7d9742750 +Initialized ref from ref 0x7ffdb2c16a50 MyObject[1] -Destructing ref 0x7ff7d9742750 -Destructing ref 0x7ff7d9742750 +Destructing ref 0x7ffdb2c16a50 +Destructing ref 0x7ffdb2c16a50 Created empty ref -Initialized ref from pointer 0x7ff7d9742750 -Move-assigning ref 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 +Move-assigning ref 0x7ffdb2c16a50 Destructing ref 0x0 MyObject[1] -Destructing ref 0x7ff7d9742750 +Destructing ref 0x7ffdb2c16a50 Created empty ref -Initialized ref from pointer 0x7ff7d9742750 -Move-assigning ref 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 +Move-assigning ref 0x7ffdb2c16a50 Destructing ref 0x0 MyObject[1] -Destructing ref 0x7ff7d9742750 +Destructing ref 0x7ffdb2c16a50 Reference count = 1 MyObject[2] Created empty ref -Initialized ref from pointer 0x7ff7d9742150 -Move-assigning ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Move-assigning ref 0x7ffdb2c167a0 Destructing ref 0x0 -Initialized ref from ref 0x7ff7d9742150 +Initialized ref from ref 0x7ffdb2c167a0 MyObject[2] -Destructing ref 0x7ff7d9742150 -Destructing ref 0x7ff7d9742150 +Destructing ref 0x7ffdb2c167a0 +Destructing ref 0x7ffdb2c167a0 Created empty ref -Initialized ref from pointer 0x7ff7d9742150 -Move-assigning ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Move-assigning ref 0x7ffdb2c167a0 Destructing ref 0x0 MyObject[2] -Destructing ref 0x7ff7d9742150 +Destructing ref 0x7ffdb2c167a0 Created empty ref -Initialized ref from pointer 0x7ff7d9742150 -Move-assigning ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Move-assigning ref 0x7ffdb2c167a0 Destructing ref 0x0 MyObject[2] -Destructing ref 0x7ff7d9742150 +Destructing ref 0x7ffdb2c167a0 Reference count = 1 MyObject[3] Created empty ref -Initialized ref from pointer 0x7ff7d9741800 -Move-assigning ref 0x7ff7d9741800 +Initialized ref from pointer 0x7ffdb2c17420 +Move-assigning ref 0x7ffdb2c17420 Destructing ref 0x0 -Initialized ref from ref 0x7ff7d9741800 +Initialized ref from ref 0x7ffdb2c17420 MyObject[3] -Destructing ref 0x7ff7d9741800 -Destructing ref 0x7ff7d9741800 +Destructing ref 0x7ffdb2c17420 +Destructing ref 0x7ffdb2c17420 Created empty ref -Initialized ref from pointer 0x7ff7d9741800 -Move-assigning ref 0x7ff7d9741800 +Initialized ref from pointer 0x7ffdb2c17420 +Move-assigning ref 0x7ffdb2c17420 Destructing ref 0x0 MyObject[3] -Destructing ref 0x7ff7d9741800 +Destructing ref 0x7ffdb2c17420 Created empty ref -Initialized ref from pointer 0x7ff7d9741800 -Move-assigning ref 0x7ff7d9741800 +Initialized ref from pointer 0x7ffdb2c17420 +Move-assigning ref 0x7ffdb2c17420 Destructing ref 0x0 MyObject[3] -Destructing ref 0x7ff7d9741800 -Destructing ref 0x7ff7d9742150 +Destructing ref 0x7ffdb2c17420 +Destructing ref 0x7ffdb2c167a0 MyObject[2] destructor -Destructing ref 0x7ff7d9742750 +Destructing ref 0x7ffdb2c16a50 MyObject[1] destructor MyObject[4] constructor -Initialized ref from pointer 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 MyObject[5] constructor -Initialized ref from pointer 0x7ff7d9742150 -Initialized ref from pointer 0x7ff7d9742150 -Destructing ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Initialized ref from pointer 0x7ffdb2c167a0 +Destructing ref 0x7ffdb2c167a0 MyObject[6] constructor -Initialized ref from pointer 0x7ff7d9741cf0 -Destructing ref 0x7ff7d9741800 +Initialized ref from pointer 0x7ffdb2c161d0 +Destructing ref 0x7ffdb2c17420 MyObject[3] destructor - + MyObject[4] Created empty ref -Initialized ref from pointer 0x7ff7d9742750 -Move-assigning ref 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 +Move-assigning ref 0x7ffdb2c16a50 Destructing ref 0x0 -Initialized ref from ref 0x7ff7d9742750 +Initialized ref from ref 0x7ffdb2c16a50 MyObject[4] -Destructing ref 0x7ff7d9742750 -Destructing ref 0x7ff7d9742750 +Destructing ref 0x7ffdb2c16a50 +Destructing ref 0x7ffdb2c16a50 Created empty ref -Initialized ref from pointer 0x7ff7d9742750 -Move-assigning ref 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 +Move-assigning ref 0x7ffdb2c16a50 Destructing ref 0x0 MyObject[4] -Destructing ref 0x7ff7d9742750 +Destructing ref 0x7ffdb2c16a50 Created empty ref -Initialized ref from pointer 0x7ff7d9742750 -Move-assigning ref 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 +Move-assigning ref 0x7ffdb2c16a50 Destructing ref 0x0 MyObject[4] -Destructing ref 0x7ff7d9742750 +Destructing ref 0x7ffdb2c16a50 MyObject[4] Created empty ref -Initialized ref from pointer 0x7ff7d9742750 -Move-assigning ref 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 +Move-assigning ref 0x7ffdb2c16a50 Destructing ref 0x0 -Initialized ref from ref 0x7ff7d9742750 +Initialized ref from ref 0x7ffdb2c16a50 MyObject[4] -Destructing ref 0x7ff7d9742750 -Destructing ref 0x7ff7d9742750 +Destructing ref 0x7ffdb2c16a50 +Destructing ref 0x7ffdb2c16a50 Created empty ref -Initialized ref from pointer 0x7ff7d9742750 -Move-assigning ref 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 +Move-assigning ref 0x7ffdb2c16a50 Destructing ref 0x0 MyObject[4] -Destructing ref 0x7ff7d9742750 +Destructing ref 0x7ffdb2c16a50 Created empty ref -Initialized ref from pointer 0x7ff7d9742750 -Move-assigning ref 0x7ff7d9742750 +Initialized ref from pointer 0x7ffdb2c16a50 +Move-assigning ref 0x7ffdb2c16a50 Destructing ref 0x0 MyObject[4] -Destructing ref 0x7ff7d9742750 - +Destructing ref 0x7ffdb2c16a50 + MyObject[5] Created empty ref -Initialized ref from pointer 0x7ff7d9742150 -Move-assigning ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Move-assigning ref 0x7ffdb2c167a0 Destructing ref 0x0 -Initialized ref from ref 0x7ff7d9742150 +Initialized ref from ref 0x7ffdb2c167a0 MyObject[5] -Destructing ref 0x7ff7d9742150 -Destructing ref 0x7ff7d9742150 +Destructing ref 0x7ffdb2c167a0 +Destructing ref 0x7ffdb2c167a0 Created empty ref -Initialized ref from pointer 0x7ff7d9742150 -Move-assigning ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Move-assigning ref 0x7ffdb2c167a0 Destructing ref 0x0 MyObject[5] -Destructing ref 0x7ff7d9742150 +Destructing ref 0x7ffdb2c167a0 Created empty ref -Initialized ref from pointer 0x7ff7d9742150 -Move-assigning ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Move-assigning ref 0x7ffdb2c167a0 Destructing ref 0x0 MyObject[5] -Destructing ref 0x7ff7d9742150 +Destructing ref 0x7ffdb2c167a0 MyObject[5] Created empty ref -Initialized ref from pointer 0x7ff7d9742150 -Move-assigning ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Move-assigning ref 0x7ffdb2c167a0 Destructing ref 0x0 -Initialized ref from ref 0x7ff7d9742150 +Initialized ref from ref 0x7ffdb2c167a0 MyObject[5] -Destructing ref 0x7ff7d9742150 -Destructing ref 0x7ff7d9742150 +Destructing ref 0x7ffdb2c167a0 +Destructing ref 0x7ffdb2c167a0 Created empty ref -Initialized ref from pointer 0x7ff7d9742150 -Move-assigning ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Move-assigning ref 0x7ffdb2c167a0 Destructing ref 0x0 MyObject[5] -Destructing ref 0x7ff7d9742150 +Destructing ref 0x7ffdb2c167a0 Created empty ref -Initialized ref from pointer 0x7ff7d9742150 -Move-assigning ref 0x7ff7d9742150 +Initialized ref from pointer 0x7ffdb2c167a0 +Move-assigning ref 0x7ffdb2c167a0 Destructing ref 0x0 MyObject[5] -Destructing ref 0x7ff7d9742150 - +Destructing ref 0x7ffdb2c167a0 + MyObject[6] Created empty ref -Initialized ref from pointer 0x7ff7d9741cf0 -Move-assigning ref 0x7ff7d9741cf0 +Initialized ref from pointer 0x7ffdb2c161d0 +Move-assigning ref 0x7ffdb2c161d0 Destructing ref 0x0 -Initialized ref from ref 0x7ff7d9741cf0 +Initialized ref from ref 0x7ffdb2c161d0 MyObject[6] -Destructing ref 0x7ff7d9741cf0 -Destructing ref 0x7ff7d9741cf0 +Destructing ref 0x7ffdb2c161d0 +Destructing ref 0x7ffdb2c161d0 Created empty ref -Initialized ref from pointer 0x7ff7d9741cf0 -Move-assigning ref 0x7ff7d9741cf0 +Initialized ref from pointer 0x7ffdb2c161d0 +Move-assigning ref 0x7ffdb2c161d0 Destructing ref 0x0 MyObject[6] -Destructing ref 0x7ff7d9741cf0 +Destructing ref 0x7ffdb2c161d0 Created empty ref -Initialized ref from pointer 0x7ff7d9741cf0 -Move-assigning ref 0x7ff7d9741cf0 +Initialized ref from pointer 0x7ffdb2c161d0 +Move-assigning ref 0x7ffdb2c161d0 Destructing ref 0x0 MyObject[6] -Destructing ref 0x7ff7d9741cf0 +Destructing ref 0x7ffdb2c161d0 MyObject[6] Created empty ref -Initialized ref from pointer 0x7ff7d9741cf0 -Move-assigning ref 0x7ff7d9741cf0 +Initialized ref from pointer 0x7ffdb2c161d0 +Move-assigning ref 0x7ffdb2c161d0 Destructing ref 0x0 -Initialized ref from ref 0x7ff7d9741cf0 +Initialized ref from ref 0x7ffdb2c161d0 MyObject[6] -Destructing ref 0x7ff7d9741cf0 -Destructing ref 0x7ff7d9741cf0 +Destructing ref 0x7ffdb2c161d0 +Destructing ref 0x7ffdb2c161d0 Created empty ref -Initialized ref from pointer 0x7ff7d9741cf0 -Move-assigning ref 0x7ff7d9741cf0 +Initialized ref from pointer 0x7ffdb2c161d0 +Move-assigning ref 0x7ffdb2c161d0 Destructing ref 0x0 MyObject[6] -Destructing ref 0x7ff7d9741cf0 +Destructing ref 0x7ffdb2c161d0 Created empty ref -Initialized ref from pointer 0x7ff7d9741cf0 -Move-assigning ref 0x7ff7d9741cf0 +Initialized ref from pointer 0x7ffdb2c161d0 +Move-assigning ref 0x7ffdb2c161d0 Destructing ref 0x0 MyObject[6] -Destructing ref 0x7ff7d9741cf0 +Destructing ref 0x7ffdb2c161d0 7 MyObject[7] constructor -Initialized ref from pointer 0x7ff7d9741800 +Initialized ref from pointer 0x7ffdb2c17420 MyObject[7] -Destructing ref 0x7ff7d9741800 +Destructing ref 0x7ffdb2c17420 MyObject[7] destructor Created empty ref MyObject[7] constructor -Initialized ref from pointer 0x7ff7d9741800 -Initialized ref from pointer 0x7ff7d9741800 -Move-assigning ref 0x7ff7d9741800 +Initialized ref from pointer 0x7ffdb2c17420 +Initialized ref from pointer 0x7ffdb2c17420 +Move-assigning ref 0x7ffdb2c17420 Destructing ref 0x0 -Initialized ref from ref 0x7ff7d9741800 +Initialized ref from ref 0x7ffdb2c17420 MyObject[7] -Destructing ref 0x7ff7d9741800 -Destructing ref 0x7ff7d9741800 -Destructing ref 0x7ff7d9741800 +Destructing ref 0x7ffdb2c17420 +Destructing ref 0x7ffdb2c17420 +Destructing ref 0x7ffdb2c17420 MyObject[7] destructor Created empty ref MyObject[7] constructor -Initialized ref from pointer 0x7ff7d9741800 -Initialized ref from pointer 0x7ff7d9741800 -Move-assigning ref 0x7ff7d9741800 +Initialized ref from pointer 0x7ffdb2c17420 +Initialized ref from pointer 0x7ffdb2c17420 +Move-assigning ref 0x7ffdb2c17420 Destructing ref 0x0 MyObject[7] -Destructing ref 0x7ff7d9741800 -Destructing ref 0x7ff7d9741800 +Destructing ref 0x7ffdb2c17420 +Destructing ref 0x7ffdb2c17420 MyObject[7] destructor Created empty ref MyObject[7] constructor -Initialized ref from pointer 0x7ff7d9741800 -Initialized ref from pointer 0x7ff7d9741800 -Move-assigning ref 0x7ff7d9741800 +Initialized ref from pointer 0x7ffdb2c17420 +Initialized ref from pointer 0x7ffdb2c17420 +Move-assigning ref 0x7ffdb2c17420 Destructing ref 0x0 MyObject[7] -Destructing ref 0x7ff7d9741800 -Destructing ref 0x7ff7d9741800 +Destructing ref 0x7ffdb2c17420 +Destructing ref 0x7ffdb2c17420 MyObject[7] destructor -Destructing ref 0x7ff7d9741cf0 +Destructing ref 0x7ffdb2c161d0 MyObject[6] destructor -Destructing ref 0x7ff7d9742150 +Destructing ref 0x7ffdb2c167a0 MyObject[5] destructor -Destructing ref 0x7ff7d9742750 +Destructing ref 0x7ffdb2c16a50 MyObject[4] destructor +MyObject2[1] constructor +MyObject2[2] constructor + +MyObject2[1] +MyObject2[1] +MyObject2[1] +MyObject2[1] + +MyObject2[2] +MyObject2[2] +MyObject2[2] +MyObject2[2] +MyObject2[1] destructor +MyObject2[2] destructor diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index ac71c9cc8..5792fab53 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -517,12 +517,25 @@ protected: template class type_caster_holder : public type_caster { public: typedef type_caster parent; + + template , T>::value, int>::type = 0> + bool load(PyObject *src, bool convert) { + if (!parent::load(src, convert)) + return false; + holder = holder_type(((type *) parent::value)->shared_from_this()); + return true; + } + + template , T>::value, int>::type = 0> bool load(PyObject *src, bool convert) { if (!parent::load(src, convert)) return false; holder = holder_type((type *) parent::value); return true; } + explicit operator type*() { return this->value; } explicit operator type&() { return *(this->value); } explicit operator holder_type&() { return holder; } diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index b8c973107..e0b1064bf 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -798,11 +798,29 @@ public: return *this; } private: + template , T>::value, int>::type = 0> static void init_holder(PyObject *inst_) { instance_type *inst = (instance_type *) inst_; new (&inst->holder) holder_type(inst->value); inst->constructed = true; } + + template , T>::value, int>::type = 0> + static void init_holder(PyObject *inst_) { + instance_type *inst = (instance_type *) inst_; + try { + new (&inst->holder) holder_type( + inst->value->shared_from_this() + ); + } catch (const std::bad_weak_ptr &) { + new (&inst->holder) holder_type(inst->value); + } + inst->constructed = true; + } + + static void dealloc(PyObject *inst_) { instance_type *inst = (instance_type *) inst_; if (inst->owned) {