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  }