github.com/kaydxh/golang@v0.0.131/pkg/gocv/cgo/third_path/pybind11/tests/test_smart_ptr.cpp (about) 1 /* 2 tests/test_smart_ptr.cpp -- binding classes with custom reference counting, 3 implicit conversions between types 4 5 Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> 6 7 All rights reserved. Use of this source code is governed by a 8 BSD-style license that can be found in the LICENSE file. 9 */ 10 11 #include "object.h" 12 #include "pybind11_tests.h" 13 14 namespace { 15 16 // This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the 17 // holder size to trigger the non-simple-layout internal instance layout for single inheritance 18 // with large holder type: 19 template <typename T> 20 class huge_unique_ptr { 21 std::unique_ptr<T> ptr; 22 uint64_t padding[10]; 23 24 public: 25 explicit huge_unique_ptr(T *p) : ptr(p) {} 26 T *get() { return ptr.get(); } 27 }; 28 29 // Simple custom holder that works like unique_ptr 30 template <typename T> 31 class custom_unique_ptr { 32 std::unique_ptr<T> impl; 33 34 public: 35 explicit custom_unique_ptr(T *p) : impl(p) {} 36 T *get() const { return impl.get(); } 37 T *release_ptr() { return impl.release(); } 38 }; 39 40 // Simple custom holder that works like shared_ptr and has operator& overload 41 // To obtain address of an instance of this holder pybind should use std::addressof 42 // Attempt to get address via operator& may leads to segmentation fault 43 template <typename T> 44 class shared_ptr_with_addressof_operator { 45 std::shared_ptr<T> impl; 46 47 public: 48 shared_ptr_with_addressof_operator() = default; 49 explicit shared_ptr_with_addressof_operator(T *p) : impl(p) {} 50 T *get() const { return impl.get(); } 51 T **operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); } 52 }; 53 54 // Simple custom holder that works like unique_ptr and has operator& overload 55 // To obtain address of an instance of this holder pybind should use std::addressof 56 // Attempt to get address via operator& may leads to segmentation fault 57 template <typename T> 58 class unique_ptr_with_addressof_operator { 59 std::unique_ptr<T> impl; 60 61 public: 62 unique_ptr_with_addressof_operator() = default; 63 explicit unique_ptr_with_addressof_operator(T *p) : impl(p) {} 64 T *get() const { return impl.get(); } 65 T *release_ptr() { return impl.release(); } 66 T **operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); } 67 }; 68 69 // Custom object with builtin reference counting (see 'object.h' for the implementation) 70 class MyObject1 : public Object { 71 public: 72 explicit MyObject1(int value) : value(value) { print_created(this, toString()); } 73 std::string toString() const override { return "MyObject1[" + std::to_string(value) + "]"; } 74 75 protected: 76 ~MyObject1() override { print_destroyed(this); } 77 78 private: 79 int value; 80 }; 81 82 // Object managed by a std::shared_ptr<> 83 class MyObject2 { 84 public: 85 MyObject2(const MyObject2 &) = default; 86 explicit MyObject2(int value) : value(value) { print_created(this, toString()); } 87 std::string toString() const { return "MyObject2[" + std::to_string(value) + "]"; } 88 virtual ~MyObject2() { print_destroyed(this); } 89 90 private: 91 int value; 92 }; 93 94 // Object managed by a std::shared_ptr<>, additionally derives from std::enable_shared_from_this<> 95 class MyObject3 : public std::enable_shared_from_this<MyObject3> { 96 public: 97 MyObject3(const MyObject3 &) = default; 98 explicit MyObject3(int value) : value(value) { print_created(this, toString()); } 99 std::string toString() const { return "MyObject3[" + std::to_string(value) + "]"; } 100 virtual ~MyObject3() { print_destroyed(this); } 101 102 private: 103 int value; 104 }; 105 106 // test_unique_nodelete 107 // Object with a private destructor 108 class MyObject4; 109 std::unordered_set<MyObject4 *> myobject4_instances; 110 class MyObject4 { 111 public: 112 explicit MyObject4(int value) : value{value} { 113 print_created(this); 114 myobject4_instances.insert(this); 115 } 116 int value; 117 118 static void cleanupAllInstances() { 119 auto tmp = std::move(myobject4_instances); 120 myobject4_instances.clear(); 121 for (auto *o : tmp) { 122 delete o; 123 } 124 } 125 126 private: 127 ~MyObject4() { 128 myobject4_instances.erase(this); 129 print_destroyed(this); 130 } 131 }; 132 133 // test_unique_deleter 134 // Object with std::unique_ptr<T, D> where D is not matching the base class 135 // Object with a protected destructor 136 class MyObject4a; 137 std::unordered_set<MyObject4a *> myobject4a_instances; 138 class MyObject4a { 139 public: 140 explicit MyObject4a(int i) : value{i} { 141 print_created(this); 142 myobject4a_instances.insert(this); 143 }; 144 int value; 145 146 static void cleanupAllInstances() { 147 auto tmp = std::move(myobject4a_instances); 148 myobject4a_instances.clear(); 149 for (auto *o : tmp) { 150 delete o; 151 } 152 } 153 154 protected: 155 virtual ~MyObject4a() { 156 myobject4a_instances.erase(this); 157 print_destroyed(this); 158 } 159 }; 160 161 // Object derived but with public destructor and no Deleter in default holder 162 class MyObject4b : public MyObject4a { 163 public: 164 explicit MyObject4b(int i) : MyObject4a(i) { print_created(this); } 165 ~MyObject4b() override { print_destroyed(this); } 166 }; 167 168 // test_large_holder 169 class MyObject5 { // managed by huge_unique_ptr 170 public: 171 explicit MyObject5(int value) : value{value} { print_created(this); } 172 ~MyObject5() { print_destroyed(this); } 173 int value; 174 }; 175 176 // test_shared_ptr_and_references 177 struct SharedPtrRef { 178 struct A { 179 A() { print_created(this); } 180 A(const A &) { print_copy_created(this); } 181 A(A &&) noexcept { print_move_created(this); } 182 ~A() { print_destroyed(this); } 183 }; 184 185 A value = {}; 186 std::shared_ptr<A> shared = std::make_shared<A>(); 187 }; 188 189 // test_shared_ptr_from_this_and_references 190 struct SharedFromThisRef { 191 struct B : std::enable_shared_from_this<B> { 192 B() { print_created(this); } 193 // NOLINTNEXTLINE(bugprone-copy-constructor-init) 194 B(const B &) : std::enable_shared_from_this<B>() { print_copy_created(this); } 195 B(B &&) noexcept : std::enable_shared_from_this<B>() { print_move_created(this); } 196 ~B() { print_destroyed(this); } 197 }; 198 199 B value = {}; 200 std::shared_ptr<B> shared = std::make_shared<B>(); 201 }; 202 203 // Issue #865: shared_from_this doesn't work with virtual inheritance 204 struct SharedFromThisVBase : std::enable_shared_from_this<SharedFromThisVBase> { 205 SharedFromThisVBase() = default; 206 SharedFromThisVBase(const SharedFromThisVBase &) = default; 207 virtual ~SharedFromThisVBase() = default; 208 }; 209 struct SharedFromThisVirt : virtual SharedFromThisVBase {}; 210 211 // test_move_only_holder 212 struct C { 213 C() { print_created(this); } 214 ~C() { print_destroyed(this); } 215 }; 216 217 // test_holder_with_addressof_operator 218 struct TypeForHolderWithAddressOf { 219 TypeForHolderWithAddressOf() { print_created(this); } 220 TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); } 221 TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) noexcept { 222 print_move_created(this); 223 } 224 ~TypeForHolderWithAddressOf() { print_destroyed(this); } 225 std::string toString() const { 226 return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]"; 227 } 228 int value = 42; 229 }; 230 231 // test_move_only_holder_with_addressof_operator 232 struct TypeForMoveOnlyHolderWithAddressOf { 233 explicit TypeForMoveOnlyHolderWithAddressOf(int value) : value{value} { print_created(this); } 234 ~TypeForMoveOnlyHolderWithAddressOf() { print_destroyed(this); } 235 std::string toString() const { 236 return "MoveOnlyHolderWithAddressOf[" + std::to_string(value) + "]"; 237 } 238 int value; 239 }; 240 241 // test_smart_ptr_from_default 242 struct HeldByDefaultHolder {}; 243 244 // test_shared_ptr_gc 245 // #187: issue involving std::shared_ptr<> return value policy & garbage collection 246 struct ElementBase { 247 virtual ~ElementBase() = default; /* Force creation of virtual table */ 248 ElementBase() = default; 249 ElementBase(const ElementBase &) = delete; 250 }; 251 252 struct ElementA : ElementBase { 253 explicit ElementA(int v) : v(v) {} 254 int value() const { return v; } 255 int v; 256 }; 257 258 struct ElementList { 259 void add(const std::shared_ptr<ElementBase> &e) { l.push_back(e); } 260 std::vector<std::shared_ptr<ElementBase>> l; 261 }; 262 263 } // namespace 264 265 // ref<T> is a wrapper for 'Object' which uses intrusive reference counting 266 // It is always possible to construct a ref<T> from an Object* pointer without 267 // possible inconsistencies, hence the 'true' argument at the end. 268 // Make pybind11 aware of the non-standard getter member function 269 namespace PYBIND11_NAMESPACE { 270 namespace detail { 271 template <typename T> 272 struct holder_helper<ref<T>> { 273 static const T *get(const ref<T> &p) { return p.get_ptr(); } 274 }; 275 } // namespace detail 276 } // namespace PYBIND11_NAMESPACE 277 278 // Make pybind aware of the ref-counted wrapper type (s): 279 PYBIND11_DECLARE_HOLDER_TYPE(T, ref<T>, true); 280 // The following is not required anymore for std::shared_ptr, but it should compile without error: 281 PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>); 282 PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>); 283 PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>); 284 PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>); 285 PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>); 286 287 TEST_SUBMODULE(smart_ptr, m) { 288 // Please do not interleave `struct` and `class` definitions with bindings code, 289 // but implement `struct`s and `class`es in the anonymous namespace above. 290 // This helps keeping the smart_holder branch in sync with master. 291 292 // test_smart_ptr 293 294 // Object implementation in `object.h` 295 py::class_<Object, ref<Object>> obj(m, "Object"); 296 obj.def("getRefCount", &Object::getRefCount); 297 298 py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj).def(py::init<int>()); 299 py::implicitly_convertible<py::int_, MyObject1>(); 300 301 m.def("make_object_1", []() -> Object * { return new MyObject1(1); }); 302 m.def("make_object_2", []() -> ref<Object> { return ref<Object>(new MyObject1(2)); }); 303 m.def("make_myobject1_1", []() -> MyObject1 * { return new MyObject1(4); }); 304 m.def("make_myobject1_2", []() -> ref<MyObject1> { return ref<MyObject1>(new MyObject1(5)); }); 305 m.def("print_object_1", [](const Object *obj) { py::print(obj->toString()); }); 306 m.def("print_object_2", [](ref<Object> obj) { py::print(obj->toString()); }); 307 m.def("print_object_3", [](const ref<Object> &obj) { py::print(obj->toString()); }); 308 m.def("print_object_4", [](const ref<Object> *obj) { py::print((*obj)->toString()); }); 309 m.def("print_myobject1_1", [](const MyObject1 *obj) { py::print(obj->toString()); }); 310 m.def("print_myobject1_2", [](ref<MyObject1> obj) { py::print(obj->toString()); }); 311 m.def("print_myobject1_3", [](const ref<MyObject1> &obj) { py::print(obj->toString()); }); 312 m.def("print_myobject1_4", [](const ref<MyObject1> *obj) { py::print((*obj)->toString()); }); 313 314 // Expose constructor stats for the ref type 315 m.def("cstats_ref", &ConstructorStats::get<ref_tag>); 316 317 py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2").def(py::init<int>()); 318 m.def("make_myobject2_1", []() { return new MyObject2(6); }); 319 m.def("make_myobject2_2", []() { return std::make_shared<MyObject2>(7); }); 320 m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); }); 321 // NOLINTNEXTLINE(performance-unnecessary-value-param) 322 m.def("print_myobject2_2", [](std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); }); 323 m.def("print_myobject2_3", 324 [](const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); }); 325 m.def("print_myobject2_4", 326 [](const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); }); 327 328 py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3").def(py::init<int>()); 329 m.def("make_myobject3_1", []() { return new MyObject3(8); }); 330 m.def("make_myobject3_2", []() { return std::make_shared<MyObject3>(9); }); 331 m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); }); 332 // NOLINTNEXTLINE(performance-unnecessary-value-param) 333 m.def("print_myobject3_2", [](std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); }); 334 m.def("print_myobject3_3", 335 [](const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); }); 336 m.def("print_myobject3_4", 337 [](const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); }); 338 339 // test_smart_ptr_refcounting 340 m.def("test_object1_refcounting", []() { 341 auto o = ref<MyObject1>(new MyObject1(0)); 342 bool good = o->getRefCount() == 1; 343 py::object o2 = py::cast(o, py::return_value_policy::reference); 344 // always request (partial) ownership for objects with intrusive 345 // reference counting even when using the 'reference' RVP 346 good &= o->getRefCount() == 2; 347 return good; 348 }); 349 350 // test_unique_nodelete 351 py::class_<MyObject4, std::unique_ptr<MyObject4, py::nodelete>>(m, "MyObject4") 352 .def(py::init<int>()) 353 .def_readwrite("value", &MyObject4::value) 354 .def_static("cleanup_all_instances", &MyObject4::cleanupAllInstances); 355 356 // test_unique_deleter 357 py::class_<MyObject4a, std::unique_ptr<MyObject4a, py::nodelete>>(m, "MyObject4a") 358 .def(py::init<int>()) 359 .def_readwrite("value", &MyObject4a::value) 360 .def_static("cleanup_all_instances", &MyObject4a::cleanupAllInstances); 361 362 py::class_<MyObject4b, MyObject4a, std::unique_ptr<MyObject4b>>(m, "MyObject4b") 363 .def(py::init<int>()); 364 365 // test_large_holder 366 py::class_<MyObject5, huge_unique_ptr<MyObject5>>(m, "MyObject5") 367 .def(py::init<int>()) 368 .def_readwrite("value", &MyObject5::value); 369 370 // test_shared_ptr_and_references 371 using A = SharedPtrRef::A; 372 py::class_<A, std::shared_ptr<A>>(m, "A"); 373 py::class_<SharedPtrRef, std::unique_ptr<SharedPtrRef>>(m, "SharedPtrRef") 374 .def(py::init<>()) 375 .def_readonly("ref", &SharedPtrRef::value) 376 .def_property_readonly( 377 "copy", [](const SharedPtrRef &s) { return s.value; }, py::return_value_policy::copy) 378 .def_readonly("holder_ref", &SharedPtrRef::shared) 379 .def_property_readonly( 380 "holder_copy", 381 [](const SharedPtrRef &s) { return s.shared; }, 382 py::return_value_policy::copy) 383 .def("set_ref", [](SharedPtrRef &, const A &) { return true; }) 384 // NOLINTNEXTLINE(performance-unnecessary-value-param) 385 .def("set_holder", [](SharedPtrRef &, std::shared_ptr<A>) { return true; }); 386 387 // test_shared_ptr_from_this_and_references 388 using B = SharedFromThisRef::B; 389 py::class_<B, std::shared_ptr<B>>(m, "B"); 390 py::class_<SharedFromThisRef, std::unique_ptr<SharedFromThisRef>>(m, "SharedFromThisRef") 391 .def(py::init<>()) 392 .def_readonly("bad_wp", &SharedFromThisRef::value) 393 .def_property_readonly("ref", 394 [](const SharedFromThisRef &s) -> const B & { return *s.shared; }) 395 .def_property_readonly( 396 "copy", 397 [](const SharedFromThisRef &s) { return s.value; }, 398 py::return_value_policy::copy) 399 .def_readonly("holder_ref", &SharedFromThisRef::shared) 400 .def_property_readonly( 401 "holder_copy", 402 [](const SharedFromThisRef &s) { return s.shared; }, 403 py::return_value_policy::copy) 404 .def("set_ref", [](SharedFromThisRef &, const B &) { return true; }) 405 // NOLINTNEXTLINE(performance-unnecessary-value-param) 406 .def("set_holder", [](SharedFromThisRef &, std::shared_ptr<B>) { return true; }); 407 408 // Issue #865: shared_from_this doesn't work with virtual inheritance 409 static std::shared_ptr<SharedFromThisVirt> sft(new SharedFromThisVirt()); 410 py::class_<SharedFromThisVirt, std::shared_ptr<SharedFromThisVirt>>(m, "SharedFromThisVirt") 411 .def_static("get", []() { return sft.get(); }); 412 413 // test_move_only_holder 414 py::class_<C, custom_unique_ptr<C>>(m, "TypeWithMoveOnlyHolder") 415 .def_static("make", []() { return custom_unique_ptr<C>(new C); }) 416 .def_static("make_as_object", []() { return py::cast(custom_unique_ptr<C>(new C)); }); 417 418 // test_holder_with_addressof_operator 419 using HolderWithAddressOf = shared_ptr_with_addressof_operator<TypeForHolderWithAddressOf>; 420 py::class_<TypeForHolderWithAddressOf, HolderWithAddressOf>(m, "TypeForHolderWithAddressOf") 421 .def_static("make", []() { return HolderWithAddressOf(new TypeForHolderWithAddressOf); }) 422 .def("get", [](const HolderWithAddressOf &self) { return self.get(); }) 423 .def("print_object_1", 424 [](const TypeForHolderWithAddressOf *obj) { py::print(obj->toString()); }) 425 // NOLINTNEXTLINE(performance-unnecessary-value-param) 426 .def("print_object_2", [](HolderWithAddressOf obj) { py::print(obj.get()->toString()); }) 427 .def("print_object_3", 428 [](const HolderWithAddressOf &obj) { py::print(obj.get()->toString()); }) 429 .def("print_object_4", 430 [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); }); 431 432 // test_move_only_holder_with_addressof_operator 433 using MoveOnlyHolderWithAddressOf 434 = unique_ptr_with_addressof_operator<TypeForMoveOnlyHolderWithAddressOf>; 435 py::class_<TypeForMoveOnlyHolderWithAddressOf, MoveOnlyHolderWithAddressOf>( 436 m, "TypeForMoveOnlyHolderWithAddressOf") 437 .def_static("make", 438 []() { 439 return MoveOnlyHolderWithAddressOf( 440 new TypeForMoveOnlyHolderWithAddressOf(0)); 441 }) 442 .def_readwrite("value", &TypeForMoveOnlyHolderWithAddressOf::value) 443 .def("print_object", 444 [](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); }); 445 446 // test_smart_ptr_from_default 447 py::class_<HeldByDefaultHolder, std::unique_ptr<HeldByDefaultHolder>>(m, "HeldByDefaultHolder") 448 .def(py::init<>()) 449 // NOLINTNEXTLINE(performance-unnecessary-value-param) 450 .def_static("load_shared_ptr", [](std::shared_ptr<HeldByDefaultHolder>) {}); 451 452 // test_shared_ptr_gc 453 // #187: issue involving std::shared_ptr<> return value policy & garbage collection 454 py::class_<ElementBase, std::shared_ptr<ElementBase>>(m, "ElementBase"); 455 456 py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m, "ElementA") 457 .def(py::init<int>()) 458 .def("value", &ElementA::value); 459 460 py::class_<ElementList, std::shared_ptr<ElementList>>(m, "ElementList") 461 .def(py::init<>()) 462 .def("add", &ElementList::add) 463 .def("get", [](ElementList &el) { 464 py::list list; 465 for (auto &e : el.l) { 466 list.append(py::cast(e)); 467 } 468 return list; 469 }); 470 }