| /* | |
| tests/test_smart_ptr.cpp -- binding classes with custom reference counting, | |
| implicit conversions between types | |
| Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> | |
| All rights reserved. Use of this source code is governed by a | |
| BSD-style license that can be found in the LICENSE file. | |
| */ | |
| #include "object.h" | |
| #include "pybind11_tests.h" | |
| // This breaks on PYBIND11_DECLARE_HOLDER_TYPE | |
| PYBIND11_WARNING_DISABLE_GCC("-Wpedantic") | |
| namespace { | |
| // This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the | |
| // holder size to trigger the non-simple-layout internal instance layout for single inheritance | |
| // with large holder type: | |
| template <typename T> | |
| class huge_unique_ptr { | |
| std::unique_ptr<T> ptr; | |
| uint64_t padding[10]; | |
| public: | |
| explicit huge_unique_ptr(T *p) : ptr(p) {} | |
| T *get() { return ptr.get(); } | |
| }; | |
| // Simple custom holder that works like unique_ptr | |
| template <typename T> | |
| class custom_unique_ptr { | |
| std::unique_ptr<T> impl; | |
| public: | |
| explicit custom_unique_ptr(T *p) : impl(p) {} | |
| T *get() const { return impl.get(); } | |
| T *release_ptr() { return impl.release(); } | |
| }; | |
| // Simple custom holder that works like shared_ptr and has operator& overload | |
| // To obtain address of an instance of this holder pybind should use std::addressof | |
| // Attempt to get address via operator& may leads to segmentation fault | |
| template <typename T> | |
| class shared_ptr_with_addressof_operator { | |
| std::shared_ptr<T> impl; | |
| public: | |
| shared_ptr_with_addressof_operator() = default; | |
| explicit shared_ptr_with_addressof_operator(T *p) : impl(p) {} | |
| T *get() const { return impl.get(); } | |
| T **operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); } | |
| }; | |
| // Simple custom holder that works like unique_ptr and has operator& overload | |
| // To obtain address of an instance of this holder pybind should use std::addressof | |
| // Attempt to get address via operator& may leads to segmentation fault | |
| template <typename T> | |
| class unique_ptr_with_addressof_operator { | |
| std::unique_ptr<T> impl; | |
| public: | |
| unique_ptr_with_addressof_operator() = default; | |
| explicit unique_ptr_with_addressof_operator(T *p) : impl(p) {} | |
| T *get() const { return impl.get(); } | |
| T *release_ptr() { return impl.release(); } | |
| T **operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); } | |
| }; | |
| // Simple custom holder that imitates smart pointer, that always stores cpointer to const | |
| template <class T> | |
| class const_only_shared_ptr { | |
| std::shared_ptr<const T> ptr_; | |
| public: | |
| const_only_shared_ptr() = default; | |
| explicit const_only_shared_ptr(const T *ptr) : ptr_(ptr) {} | |
| const T *get() const { return ptr_.get(); } | |
| private: | |
| // for demonstration purpose only, this imitates smart pointer with a const-only pointer | |
| }; | |
| template <typename T> | |
| class shared_ptr_as_custom_holder { | |
| std::shared_ptr<T> ptr_; | |
| public: | |
| using element_type = T; | |
| shared_ptr_as_custom_holder() = default; | |
| explicit shared_ptr_as_custom_holder(T *) { | |
| throw std::runtime_error("invalid shared_ptr_as_custom_holder constructor call"); | |
| } | |
| explicit shared_ptr_as_custom_holder(std::shared_ptr<T> ptr) : ptr_(std::move(ptr)) {} | |
| T *get() const { return ptr_.get(); } | |
| }; | |
| // Custom object with builtin reference counting (see 'object.h' for the implementation) | |
| class MyObject1 : public Object { | |
| public: | |
| explicit MyObject1(int value) : value(value) { print_created(this, toString()); } | |
| std::string toString() const override { return "MyObject1[" + std::to_string(value) + "]"; } | |
| protected: | |
| ~MyObject1() override { print_destroyed(this); } | |
| private: | |
| int value; | |
| }; | |
| // Object managed by a std::shared_ptr<> | |
| class MyObject2 { | |
| public: | |
| MyObject2(const MyObject2 &) = default; | |
| explicit MyObject2(int value) : value(value) { print_created(this, toString()); } | |
| std::string toString() const { return "MyObject2[" + std::to_string(value) + "]"; } | |
| virtual ~MyObject2() { print_destroyed(this); } | |
| private: | |
| int value; | |
| }; | |
| // Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<> | |
| class MyObject3 : public std::enable_shared_from_this<MyObject3> { | |
| public: | |
| MyObject3(const MyObject3 &) = default; | |
| explicit MyObject3(int value) : value(value) { print_created(this, toString()); } | |
| std::string toString() const { return "MyObject3[" + std::to_string(value) + "]"; } | |
| virtual ~MyObject3() { print_destroyed(this); } | |
| private: | |
| int value; | |
| }; | |
| template <typename T> | |
| std::unordered_set<T *> &pointer_set() { | |
| // https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables | |
| static auto singleton = new std::unordered_set<T *>(); | |
| return *singleton; | |
| } | |
| // test_unique_nodelete | |
| // Object with a private destructor | |
| class MyObject4 { | |
| public: | |
| explicit MyObject4(int value) : value{value} { | |
| print_created(this); | |
| pointer_set<MyObject4>().insert(this); | |
| } | |
| int value; | |
| static void cleanupAllInstances() { | |
| auto tmp = std::move(pointer_set<MyObject4>()); | |
| pointer_set<MyObject4>().clear(); | |
| for (auto *o : tmp) { | |
| delete o; | |
| } | |
| } | |
| private: | |
| ~MyObject4() { | |
| pointer_set<MyObject4>().erase(this); | |
| print_destroyed(this); | |
| } | |
| }; | |
| // test_unique_deleter | |
| // Object with std::unique_ptr<T, D> where D is not matching the base class | |
| // Object with a protected destructor | |
| class MyObject4a { | |
| public: | |
| explicit MyObject4a(int i) : value{i} { | |
| print_created(this); | |
| pointer_set<MyObject4a>().insert(this); | |
| }; | |
| MyObject4a(const MyObject4a &) = delete; | |
| int value; | |
| static void cleanupAllInstances() { | |
| auto tmp = std::move(pointer_set<MyObject4a>()); | |
| pointer_set<MyObject4a>().clear(); | |
| for (auto *o : tmp) { | |
| delete o; | |
| } | |
| } | |
| protected: | |
| virtual ~MyObject4a() { | |
| pointer_set<MyObject4a>().erase(this); | |
| print_destroyed(this); | |
| } | |
| }; | |
| // Object derived but with public destructor and no Deleter in default holder | |
| class MyObject4b : public MyObject4a { | |
| public: | |
| explicit MyObject4b(int i) : MyObject4a(i) { print_created(this); } | |
| MyObject4b(const MyObject4b &) = delete; | |
| ~MyObject4b() override { print_destroyed(this); } | |
| }; | |
| // test_large_holder | |
| class MyObject5 { // managed by huge_unique_ptr | |
| public: | |
| explicit MyObject5(int value) : value{value} { print_created(this); } | |
| MyObject5(const MyObject5 &) = delete; | |
| ~MyObject5() { print_destroyed(this); } | |
| int value; | |
| }; | |
| // test const_only_shared_ptr | |
| class MyObject6 { | |
| public: | |
| static const_only_shared_ptr<MyObject6> createObject(std::string value) { | |
| return const_only_shared_ptr<MyObject6>(new MyObject6(std::move(value))); | |
| } | |
| const std::string &value() const { return value_; } | |
| private: | |
| explicit MyObject6(std::string &&value) : value_{std::move(value)} {} | |
| std::string value_; | |
| }; | |
| // test_shared_ptr_and_references | |
| struct SharedPtrRef { | |
| struct A { | |
| A() { print_created(this); } | |
| A(const A &) { print_copy_created(this); } | |
| A(A &&) noexcept { print_move_created(this); } | |
| ~A() { print_destroyed(this); } | |
| }; | |
| A value; | |
| std::shared_ptr<A> shared = std::make_shared<A>(); | |
| }; | |
| // test_shared_ptr_from_this_and_references | |
| struct SharedFromThisRef { | |
| struct B : std::enable_shared_from_this<B> { | |
| B() { print_created(this); } | |
| // NOLINTNEXTLINE(bugprone-copy-constructor-init, readability-redundant-member-init) | |
| B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); } | |
| // NOLINTNEXTLINE(readability-redundant-member-init) | |
| B(B &&) noexcept : std::enable_shared_from_this<B>() { print_move_created(this); } | |
| ~B() { print_destroyed(this); } | |
| }; | |
| B value; | |
| std::shared_ptr<B> shared = std::make_shared<B>(); | |
| }; | |
| class Issue6064UnsafePath { | |
| public: | |
| static std::shared_ptr<Issue6064UnsafePath> create() { | |
| return {new Issue6064UnsafePath(), [](Issue6064UnsafePath *ptr) { delete ptr; }}; | |
| } | |
| private: | |
| Issue6064UnsafePath() = default; | |
| ~Issue6064UnsafePath() = default; | |
| }; | |
| // Issue #865: shared_from_this doesn't work with virtual inheritance | |
| struct SharedFromThisVBase : std::enable_shared_from_this<SharedFromThisVBase> { | |
| SharedFromThisVBase() = default; | |
| SharedFromThisVBase(const SharedFromThisVBase &) = default; | |
| virtual ~SharedFromThisVBase() = default; | |
| }; | |
| struct SharedFromThisVirt : virtual SharedFromThisVBase {}; | |
| // Issue #5989: static_pointer_cast where dynamic_pointer_cast is needed | |
| // (virtual inheritance with shared_ptr holder) | |
| struct SftVirtBase : std::enable_shared_from_this<SftVirtBase> { | |
| SftVirtBase() = default; | |
| virtual ~SftVirtBase() = default; | |
| static std::shared_ptr<SftVirtBase> create() { return std::make_shared<SftVirtBase>(); } | |
| virtual std::string name() { return "SftVirtBase"; } | |
| }; | |
| struct SftVirtDerived : SftVirtBase { | |
| using SftVirtBase::SftVirtBase; | |
| static std::shared_ptr<SftVirtDerived> create() { return std::make_shared<SftVirtDerived>(); } | |
| std::string name() override { return "SftVirtDerived"; } | |
| }; | |
| struct SftVirtDerived2 : virtual SftVirtDerived { | |
| using SftVirtDerived::SftVirtDerived; | |
| static std::shared_ptr<SftVirtDerived2> create() { | |
| return std::make_shared<SftVirtDerived2>(); | |
| } | |
| std::string name() override { return "SftVirtDerived2"; } | |
| std::string call_name(const std::shared_ptr<SftVirtDerived2> &d2) { return d2->name(); } | |
| }; | |
| // test_move_only_holder | |
| struct C { | |
| C() { print_created(this); } | |
| C(const C &) = delete; | |
| ~C() { print_destroyed(this); } | |
| }; | |
| // test_holder_with_addressof_operator | |
| struct TypeForHolderWithAddressOf { | |
| TypeForHolderWithAddressOf() { print_created(this); } | |
| TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); } | |
| TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) noexcept { | |
| print_move_created(this); | |
| } | |
| ~TypeForHolderWithAddressOf() { print_destroyed(this); } | |
| std::string toString() const { | |
| return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]"; | |
| } | |
| int value = 42; | |
| }; | |
| // test_move_only_holder_with_addressof_operator | |
| struct TypeForMoveOnlyHolderWithAddressOf { | |
| explicit TypeForMoveOnlyHolderWithAddressOf(int value) : value{value} { print_created(this); } | |
| TypeForMoveOnlyHolderWithAddressOf(const TypeForMoveOnlyHolderWithAddressOf &) = delete; | |
| ~TypeForMoveOnlyHolderWithAddressOf() { print_destroyed(this); } | |
| std::string toString() const { | |
| return "MoveOnlyHolderWithAddressOf[" + std::to_string(value) + "]"; | |
| } | |
| int value; | |
| }; | |
| // test_smart_ptr_from_default | |
| struct HeldByDefaultHolder {}; | |
| // test_shared_ptr_gc | |
| // #187: issue involving std::shared_ptr<> return value policy & garbage collection | |
| struct ElementBase { | |
| virtual ~ElementBase() = default; /* Force creation of virtual table */ | |
| ElementBase() = default; | |
| ElementBase(const ElementBase &) = delete; | |
| }; | |
| struct ElementA : ElementBase { | |
| explicit ElementA(int v) : v(v) {} | |
| int value() const { return v; } | |
| int v; | |
| }; | |
| struct ElementList { | |
| void add(const std::shared_ptr<ElementBase> &e) { l.push_back(e); } | |
| std::vector<std::shared_ptr<ElementBase>> l; | |
| }; | |
| } // namespace | |
| // ref<T> is a wrapper for 'Object' which uses intrusive reference counting | |
| // It is always possible to construct a ref<T> from an Object* pointer without | |
| // possible inconsistencies, hence the 'true' argument at the end. | |
| // Make pybind11 aware of the non-standard getter member function | |
| namespace PYBIND11_NAMESPACE { | |
| namespace detail { | |
| template <typename T> | |
| struct holder_helper<ref<T>> { | |
| static const T *get(const ref<T> &p) { return p.get_ptr(); } | |
| }; | |
| } // namespace detail | |
| } // namespace PYBIND11_NAMESPACE | |
| // Make pybind aware of the ref-counted wrapper type (s): | |
| PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true) | |
| PYBIND11_DECLARE_HOLDER_TYPE(T, const_only_shared_ptr<T>, true) | |
| PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_as_custom_holder<T>, ) | |
| // The following is not required anymore for std::shared_ptr, but it should compile without error: | |
| PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>, ) | |
| PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>, ) | |
| PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>, ) | |
| PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>, ) | |
| PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>, ) | |
| namespace holder_caster_traits_test { | |
| struct example_base {}; | |
| } // namespace holder_caster_traits_test | |
| PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) | |
| PYBIND11_NAMESPACE_BEGIN(detail) | |
| // Negate this condition to demonstrate "ambiguous template instantiation" compilation error: | |
| #if defined(PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT) | |
| template <typename ExampleType> | |
| struct copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled< | |
| ExampleType, | |
| enable_if_t<std::is_base_of<holder_caster_traits_test::example_base, ExampleType>::value>> | |
| : std::false_type {}; | |
| #endif | |
| template <typename ExampleType, typename HolderType> | |
| struct copyable_holder_caster< | |
| ExampleType, | |
| HolderType, | |
| enable_if_t<std::is_base_of<holder_caster_traits_test::example_base, ExampleType>::value>> { | |
| static constexpr auto name = const_name<ExampleType>(); | |
| static handle cast(const HolderType &, return_value_policy, handle) { | |
| return str("copyable_holder_caster_traits_test").release(); | |
| } | |
| }; | |
| // Negate this condition to demonstrate "ambiguous template instantiation" compilation error: | |
| #if defined(PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT) | |
| template <typename ExampleType> | |
| struct move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled< | |
| ExampleType, | |
| enable_if_t<std::is_base_of<holder_caster_traits_test::example_base, ExampleType>::value>> | |
| : std::false_type {}; | |
| #endif | |
| template <typename ExampleType, typename HolderType> | |
| struct move_only_holder_caster< | |
| ExampleType, | |
| HolderType, | |
| enable_if_t<std::is_base_of<holder_caster_traits_test::example_base, ExampleType>::value>> { | |
| static constexpr auto name = const_name<ExampleType>(); | |
| static handle cast(const HolderType &, return_value_policy, handle) { | |
| return str("move_only_holder_caster_traits_test").release(); | |
| } | |
| }; | |
| PYBIND11_NAMESPACE_END(detail) | |
| PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) | |
| namespace holder_caster_traits_test { | |
| struct example_drvd : example_base {}; | |
| void wrap(py::module_ &m) { | |
| m.def("return_std_shared_ptr_example_drvd", | |
| // NOLINTNEXTLINE(modernize-make-shared) | |
| []() { return std::shared_ptr<example_drvd>(new example_drvd()); }); | |
| m.def("return_std_unique_ptr_example_drvd", | |
| []() { return std::unique_ptr<example_drvd>(new example_drvd()); }); | |
| } | |
| } // namespace holder_caster_traits_test | |
| TEST_SUBMODULE(smart_ptr, m) { | |
| // Please do not interleave `struct` and `class` definitions with bindings code, | |
| // but implement `struct`s and `class`es in the anonymous namespace above. | |
| // This helps keeping the smart_holder branch in sync with master. | |
| // test_smart_ptr | |
| // Object implementation in `object.h` | |
| py::class_<Object, ref<Object>> obj(m, "Object"); | |
| obj.def("getRefCount", &Object::getRefCount); | |
| py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj).def(py::init<int>()); | |
| py::implicitly_convertible<py::int_, MyObject1>(); | |
| m.def("make_object_1", []() -> Object * { return new MyObject1(1); }); | |
| m.def("make_object_2", []() -> ref<Object> { return ref<Object>(new MyObject1(2)); }); | |
| m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); }); | |
| m.def("make_myobject1_2", []() -> ref<MyObject1> { return ref<MyObject1>(new MyObject1(5)); }); | |
| m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); }); | |
| m.def("print_object_2", [](ref<Object> obj) { py::print(obj->toString()); }); | |
| m.def("print_object_3", [](const ref<Object> &obj) { py::print(obj->toString()); }); | |
| m.def("print_object_4", [](const ref<Object> *obj) { py::print((*obj)->toString()); }); | |
| m.def("print_myobject1_1", [](const MyObject1 *obj) { py::print(obj->toString()); }); | |
| m.def("print_myobject1_2", [](ref<MyObject1> obj) { py::print(obj->toString()); }); | |
| m.def("print_myobject1_3", [](const ref<MyObject1> &obj) { py::print(obj->toString()); }); | |
| m.def("print_myobject1_4", [](const ref<MyObject1> *obj) { py::print((*obj)->toString()); }); | |
| // Expose constructor stats for the ref type | |
| m.def("cstats_ref", &ConstructorStats::get<ref_tag>); | |
| py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2").def(py::init<int>()); | |
| m.def("make_myobject2_1", []() { return new MyObject2(6); }); | |
| m.def("make_myobject2_2", []() { return std::make_shared<MyObject2>(7); }); | |
| m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); }); | |
| // NOLINTNEXTLINE(performance-unnecessary-value-param) | |
| m.def("print_myobject2_2", [](std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); }); | |
| m.def("print_myobject2_3", | |
| [](const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); }); | |
| m.def("print_myobject2_4", | |
| [](const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); }); | |
| py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3").def(py::init<int>()); | |
| m.def("make_myobject3_1", []() { return new MyObject3(8); }); | |
| m.def("make_myobject3_2", []() { return std::make_shared<MyObject3>(9); }); | |
| m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); }); | |
| // NOLINTNEXTLINE(performance-unnecessary-value-param) | |
| m.def("print_myobject3_2", [](std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); }); | |
| m.def("print_myobject3_3", | |
| [](const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); }); | |
| m.def("print_myobject3_4", | |
| [](const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); }); | |
| // test_smart_ptr_refcounting | |
| m.def("test_object1_refcounting", []() { | |
| auto o = ref<MyObject1>(new MyObject1(0)); | |
| bool good = o->getRefCount() == 1; | |
| py::object o2 = py::cast(o, py::return_value_policy::reference); | |
| // always request (partial) ownership for objects with intrusive | |
| // reference counting even when using the 'reference' RVP | |
| good &= o->getRefCount() == 2; | |
| return good; | |
| }); | |
| // test_unique_nodelete | |
| py::class_<MyObject4, std::unique_ptr<MyObject4, py::nodelete>>(m, "MyObject4") | |
| .def(py::init<int>()) | |
| .def_readwrite("value", &MyObject4::value) | |
| .def_static("cleanup_all_instances", &MyObject4::cleanupAllInstances); | |
| // test_unique_deleter | |
| py::class_<MyObject4a, std::unique_ptr<MyObject4a, py::nodelete>>(m, "MyObject4a") | |
| .def(py::init<int>()) | |
| .def_readwrite("value", &MyObject4a::value) | |
| .def_static("cleanup_all_instances", &MyObject4a::cleanupAllInstances); | |
| py::class_<MyObject4b, MyObject4a, std::unique_ptr<MyObject4b>>(m, "MyObject4b") | |
| .def(py::init<int>()); | |
| // test_large_holder | |
| py::class_<MyObject5, huge_unique_ptr<MyObject5>>(m, "MyObject5") | |
| .def(py::init<int>()) | |
| .def_readwrite("value", &MyObject5::value); | |
| py::class_<MyObject6, const_only_shared_ptr<MyObject6>>(m, "MyObject6") | |
| .def(py::init([](const std::string &value) { return MyObject6::createObject(value); })) | |
| .def_property_readonly("value", &MyObject6::value); | |
| py::class_<Issue6064UnsafePath, shared_ptr_as_custom_holder<Issue6064UnsafePath>>( | |
| m, "Issue6064UnsafePath"); | |
| m.def("get_issue6064_unsafe_path_shared_ptr", []() { return Issue6064UnsafePath::create(); }); | |
| // test_shared_ptr_and_references | |
| using A = SharedPtrRef::A; | |
| py::class_<A, std::shared_ptr<A>>(m, "A"); | |
| py::class_<SharedPtrRef, std::unique_ptr<SharedPtrRef>>(m, "SharedPtrRef") | |
| .def(py::init<>()) | |
| .def_readonly("ref", &SharedPtrRef::value) | |
| .def_property_readonly( | |
| "copy", [](const SharedPtrRef &s) { return s.value; }, py::return_value_policy::copy) | |
| .def_readonly("holder_ref", &SharedPtrRef::shared) | |
| .def_property_readonly( | |
| "holder_copy", | |
| [](const SharedPtrRef &s) { return s.shared; }, | |
| py::return_value_policy::copy) | |
| .def("set_ref", [](SharedPtrRef &, const A &) { return true; }) | |
| // NOLINTNEXTLINE(performance-unnecessary-value-param) | |
| .def("set_holder", [](SharedPtrRef &, std::shared_ptr<A>) { return true; }); | |
| // test_shared_ptr_from_this_and_references | |
| using B = SharedFromThisRef::B; | |
| py::class_<B, std::shared_ptr<B>>(m, "B"); | |
| py::class_<SharedFromThisRef, std::unique_ptr<SharedFromThisRef>>(m, "SharedFromThisRef") | |
| .def(py::init<>()) | |
| .def_readonly("bad_wp", &SharedFromThisRef::value) | |
| .def_property_readonly("ref", | |
| [](const SharedFromThisRef &s) -> const B & { return *s.shared; }) | |
| .def_property_readonly( | |
| "copy", | |
| [](const SharedFromThisRef &s) { return s.value; }, | |
| py::return_value_policy::copy) | |
| .def_readonly("holder_ref", &SharedFromThisRef::shared) | |
| .def_property_readonly( | |
| "holder_copy", | |
| [](const SharedFromThisRef &s) { return s.shared; }, | |
| py::return_value_policy::copy) | |
| .def("set_ref", [](SharedFromThisRef &, const B &) { return true; }) | |
| // NOLINTNEXTLINE(performance-unnecessary-value-param) | |
| .def("set_holder", [](SharedFromThisRef &, std::shared_ptr<B>) { return true; }); | |
| // Issue #865: shared_from_this doesn't work with virtual inheritance | |
| static std::shared_ptr<SharedFromThisVirt> sft(new SharedFromThisVirt()); | |
| py::class_<SharedFromThisVirt, std::shared_ptr<SharedFromThisVirt>>(m, "SharedFromThisVirt") | |
| .def_static("get", []() { return sft.get(); }); | |
| // Issue #5989: static_pointer_cast where dynamic_pointer_cast is needed | |
| py::class_<SftVirtBase, std::shared_ptr<SftVirtBase>>(m, "SftVirtBase") | |
| .def(py::init<>(&SftVirtBase::create)) | |
| .def("name", &SftVirtBase::name); | |
| py::class_<SftVirtDerived, SftVirtBase, std::shared_ptr<SftVirtDerived>>(m, "SftVirtDerived") | |
| .def(py::init<>(&SftVirtDerived::create)); | |
| py::class_<SftVirtDerived2, SftVirtDerived, std::shared_ptr<SftVirtDerived2>>( | |
| m, "SftVirtDerived2") | |
| .def(py::init<>(&SftVirtDerived2::create)) | |
| .def("call_name", &SftVirtDerived2::call_name, py::arg("d2")); | |
| // test_move_only_holder | |
| py::class_<C, custom_unique_ptr<C>>(m, "TypeWithMoveOnlyHolder") | |
| .def_static("make", []() { return custom_unique_ptr<C>(new C); }) | |
| .def_static("make_as_object", []() { return py::cast(custom_unique_ptr<C>(new C)); }); | |
| m.def("get_type_with_move_only_holder_shared_ptr", []() { return std::make_shared<C>(); }); | |
| // test_holder_with_addressof_operator | |
| using HolderWithAddressOf = shared_ptr_with_addressof_operator<TypeForHolderWithAddressOf>; | |
| py::class_<TypeForHolderWithAddressOf, HolderWithAddressOf>(m, "TypeForHolderWithAddressOf") | |
| .def_static("make", []() { return HolderWithAddressOf(new TypeForHolderWithAddressOf); }) | |
| .def("get", [](const HolderWithAddressOf &self) { return self.get(); }) | |
| .def("print_object_1", | |
| [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); }) | |
| // NOLINTNEXTLINE(performance-unnecessary-value-param) | |
| .def("print_object_2", [](HolderWithAddressOf obj) { py::print(obj.get()->toString()); }) | |
| .def("print_object_3", | |
| [](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); }) | |
| .def("print_object_4", | |
| [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); }); | |
| // test_move_only_holder_with_addressof_operator | |
| using MoveOnlyHolderWithAddressOf | |
| = unique_ptr_with_addressof_operator<TypeForMoveOnlyHolderWithAddressOf>; | |
| py::class_<TypeForMoveOnlyHolderWithAddressOf, MoveOnlyHolderWithAddressOf>( | |
| m, "TypeForMoveOnlyHolderWithAddressOf") | |
| .def_static("make", | |
| []() { | |
| return MoveOnlyHolderWithAddressOf( | |
| new TypeForMoveOnlyHolderWithAddressOf(0)); | |
| }) | |
| .def_readwrite("value", &TypeForMoveOnlyHolderWithAddressOf::value) | |
| .def("print_object", | |
| [](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); }); | |
| // test_smart_ptr_from_default | |
| py::class_<HeldByDefaultHolder, std::unique_ptr<HeldByDefaultHolder>>(m, "HeldByDefaultHolder") | |
| .def(py::init<>()) | |
| // NOLINTNEXTLINE(performance-unnecessary-value-param) | |
| .def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {}); | |
| // test_shared_ptr_gc | |
| // #187: issue involving std::shared_ptr<> return value policy & garbage collection | |
| py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase"); | |
| py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m, "ElementA") | |
| .def(py::init<int>()) | |
| .def("value", &ElementA::value); | |
| py::class_<ElementList, std::shared_ptr<ElementList>>(m, "ElementList") | |
| .def(py::init<>()) | |
| .def("add", &ElementList::add) | |
| .def("get", [](ElementList &el) { | |
| py::list list; | |
| for (auto &e : el.l) { | |
| list.append(py::cast(e)); | |
| } | |
| return list; | |
| }); | |
| // NOLINTNEXTLINE(bugprone-incorrect-enable-shared-from-this) | |
| class PrivateESFT : /* implicit private */ std::enable_shared_from_this<PrivateESFT> {}; | |
| struct ContainerUsingPrivateESFT { | |
| std::shared_ptr<PrivateESFT> ptr; | |
| }; | |
| py::class_<ContainerUsingPrivateESFT>(m, "ContainerUsingPrivateESFT") | |
| .def(py::init<>()) | |
| .def_readwrite("ptr", | |
| &ContainerUsingPrivateESFT::ptr); // <- access ESFT through shared_ptr | |
| holder_caster_traits_test::wrap(m); | |
| } |