test_smart_ptr.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. # -*- coding: utf-8 -*-
  2. import pytest
  3. m = pytest.importorskip("pybind11_tests.smart_ptr")
  4. from pybind11_tests import ConstructorStats # noqa: E402
  5. def test_smart_ptr(capture):
  6. # Object1
  7. for i, o in enumerate(
  8. [m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1
  9. ):
  10. assert o.getRefCount() == 1
  11. with capture:
  12. m.print_object_1(o)
  13. m.print_object_2(o)
  14. m.print_object_3(o)
  15. m.print_object_4(o)
  16. assert capture == "MyObject1[{i}]\n".format(i=i) * 4
  17. for i, o in enumerate(
  18. [m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], start=4
  19. ):
  20. print(o)
  21. with capture:
  22. if not isinstance(o, int):
  23. m.print_object_1(o)
  24. m.print_object_2(o)
  25. m.print_object_3(o)
  26. m.print_object_4(o)
  27. m.print_myobject1_1(o)
  28. m.print_myobject1_2(o)
  29. m.print_myobject1_3(o)
  30. m.print_myobject1_4(o)
  31. times = 4 if isinstance(o, int) else 8
  32. assert capture == "MyObject1[{i}]\n".format(i=i) * times
  33. cstats = ConstructorStats.get(m.MyObject1)
  34. assert cstats.alive() == 0
  35. expected_values = ["MyObject1[{}]".format(i) for i in range(1, 7)] + [
  36. "MyObject1[7]"
  37. ] * 4
  38. assert cstats.values() == expected_values
  39. assert cstats.default_constructions == 0
  40. assert cstats.copy_constructions == 0
  41. # assert cstats.move_constructions >= 0 # Doesn't invoke any
  42. assert cstats.copy_assignments == 0
  43. assert cstats.move_assignments == 0
  44. # Object2
  45. for i, o in zip(
  46. [8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]
  47. ):
  48. print(o)
  49. with capture:
  50. m.print_myobject2_1(o)
  51. m.print_myobject2_2(o)
  52. m.print_myobject2_3(o)
  53. m.print_myobject2_4(o)
  54. assert capture == "MyObject2[{i}]\n".format(i=i) * 4
  55. cstats = ConstructorStats.get(m.MyObject2)
  56. assert cstats.alive() == 1
  57. o = None
  58. assert cstats.alive() == 0
  59. assert cstats.values() == ["MyObject2[8]", "MyObject2[6]", "MyObject2[7]"]
  60. assert cstats.default_constructions == 0
  61. assert cstats.copy_constructions == 0
  62. # assert cstats.move_constructions >= 0 # Doesn't invoke any
  63. assert cstats.copy_assignments == 0
  64. assert cstats.move_assignments == 0
  65. # Object3
  66. for i, o in zip(
  67. [9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]
  68. ):
  69. print(o)
  70. with capture:
  71. m.print_myobject3_1(o)
  72. m.print_myobject3_2(o)
  73. m.print_myobject3_3(o)
  74. m.print_myobject3_4(o)
  75. assert capture == "MyObject3[{i}]\n".format(i=i) * 4
  76. cstats = ConstructorStats.get(m.MyObject3)
  77. assert cstats.alive() == 1
  78. o = None
  79. assert cstats.alive() == 0
  80. assert cstats.values() == ["MyObject3[9]", "MyObject3[8]", "MyObject3[9]"]
  81. assert cstats.default_constructions == 0
  82. assert cstats.copy_constructions == 0
  83. # assert cstats.move_constructions >= 0 # Doesn't invoke any
  84. assert cstats.copy_assignments == 0
  85. assert cstats.move_assignments == 0
  86. # Object
  87. cstats = ConstructorStats.get(m.Object)
  88. assert cstats.alive() == 0
  89. assert cstats.values() == []
  90. assert cstats.default_constructions == 10
  91. assert cstats.copy_constructions == 0
  92. # assert cstats.move_constructions >= 0 # Doesn't invoke any
  93. assert cstats.copy_assignments == 0
  94. assert cstats.move_assignments == 0
  95. # ref<>
  96. cstats = m.cstats_ref()
  97. assert cstats.alive() == 0
  98. assert cstats.values() == ["from pointer"] * 10
  99. assert cstats.default_constructions == 30
  100. assert cstats.copy_constructions == 12
  101. # assert cstats.move_constructions >= 0 # Doesn't invoke any
  102. assert cstats.copy_assignments == 30
  103. assert cstats.move_assignments == 0
  104. def test_smart_ptr_refcounting():
  105. assert m.test_object1_refcounting()
  106. def test_unique_nodelete():
  107. o = m.MyObject4(23)
  108. assert o.value == 23
  109. cstats = ConstructorStats.get(m.MyObject4)
  110. assert cstats.alive() == 1
  111. del o
  112. assert cstats.alive() == 1
  113. m.MyObject4.cleanup_all_instances()
  114. assert cstats.alive() == 0
  115. def test_unique_nodelete4a():
  116. o = m.MyObject4a(23)
  117. assert o.value == 23
  118. cstats = ConstructorStats.get(m.MyObject4a)
  119. assert cstats.alive() == 1
  120. del o
  121. assert cstats.alive() == 1
  122. m.MyObject4a.cleanup_all_instances()
  123. assert cstats.alive() == 0
  124. def test_unique_deleter():
  125. m.MyObject4a(0)
  126. o = m.MyObject4b(23)
  127. assert o.value == 23
  128. cstats4a = ConstructorStats.get(m.MyObject4a)
  129. assert cstats4a.alive() == 2
  130. cstats4b = ConstructorStats.get(m.MyObject4b)
  131. assert cstats4b.alive() == 1
  132. del o
  133. assert cstats4a.alive() == 1 # Should now only be one leftover
  134. assert cstats4b.alive() == 0 # Should be deleted
  135. m.MyObject4a.cleanup_all_instances()
  136. assert cstats4a.alive() == 0
  137. assert cstats4b.alive() == 0
  138. def test_large_holder():
  139. o = m.MyObject5(5)
  140. assert o.value == 5
  141. cstats = ConstructorStats.get(m.MyObject5)
  142. assert cstats.alive() == 1
  143. del o
  144. assert cstats.alive() == 0
  145. def test_shared_ptr_and_references():
  146. s = m.SharedPtrRef()
  147. stats = ConstructorStats.get(m.A)
  148. assert stats.alive() == 2
  149. ref = s.ref # init_holder_helper(holder_ptr=false, owned=false)
  150. assert stats.alive() == 2
  151. assert s.set_ref(ref)
  152. with pytest.raises(RuntimeError) as excinfo:
  153. assert s.set_holder(ref)
  154. assert "Unable to cast from non-held to held instance" in str(excinfo.value)
  155. copy = s.copy # init_holder_helper(holder_ptr=false, owned=true)
  156. assert stats.alive() == 3
  157. assert s.set_ref(copy)
  158. assert s.set_holder(copy)
  159. holder_ref = s.holder_ref # init_holder_helper(holder_ptr=true, owned=false)
  160. assert stats.alive() == 3
  161. assert s.set_ref(holder_ref)
  162. assert s.set_holder(holder_ref)
  163. holder_copy = s.holder_copy # init_holder_helper(holder_ptr=true, owned=true)
  164. assert stats.alive() == 3
  165. assert s.set_ref(holder_copy)
  166. assert s.set_holder(holder_copy)
  167. del ref, copy, holder_ref, holder_copy, s
  168. assert stats.alive() == 0
  169. def test_shared_ptr_from_this_and_references():
  170. s = m.SharedFromThisRef()
  171. stats = ConstructorStats.get(m.B)
  172. assert stats.alive() == 2
  173. ref = s.ref # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
  174. assert stats.alive() == 2
  175. assert s.set_ref(ref)
  176. assert s.set_holder(
  177. ref
  178. ) # std::enable_shared_from_this can create a holder from a reference
  179. bad_wp = s.bad_wp # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
  180. assert stats.alive() == 2
  181. assert s.set_ref(bad_wp)
  182. with pytest.raises(RuntimeError) as excinfo:
  183. assert s.set_holder(bad_wp)
  184. assert "Unable to cast from non-held to held instance" in str(excinfo.value)
  185. copy = s.copy # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
  186. assert stats.alive() == 3
  187. assert s.set_ref(copy)
  188. assert s.set_holder(copy)
  189. holder_ref = (
  190. s.holder_ref
  191. ) # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
  192. assert stats.alive() == 3
  193. assert s.set_ref(holder_ref)
  194. assert s.set_holder(holder_ref)
  195. holder_copy = (
  196. s.holder_copy
  197. ) # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
  198. assert stats.alive() == 3
  199. assert s.set_ref(holder_copy)
  200. assert s.set_holder(holder_copy)
  201. del ref, bad_wp, copy, holder_ref, holder_copy, s
  202. assert stats.alive() == 0
  203. z = m.SharedFromThisVirt.get()
  204. y = m.SharedFromThisVirt.get()
  205. assert y is z
  206. def test_move_only_holder():
  207. a = m.TypeWithMoveOnlyHolder.make()
  208. b = m.TypeWithMoveOnlyHolder.make_as_object()
  209. stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder)
  210. assert stats.alive() == 2
  211. del b
  212. assert stats.alive() == 1
  213. del a
  214. assert stats.alive() == 0
  215. def test_holder_with_addressof_operator():
  216. # this test must not throw exception from c++
  217. a = m.TypeForHolderWithAddressOf.make()
  218. a.print_object_1()
  219. a.print_object_2()
  220. a.print_object_3()
  221. a.print_object_4()
  222. stats = ConstructorStats.get(m.TypeForHolderWithAddressOf)
  223. assert stats.alive() == 1
  224. np = m.TypeForHolderWithAddressOf.make()
  225. assert stats.alive() == 2
  226. del a
  227. assert stats.alive() == 1
  228. del np
  229. assert stats.alive() == 0
  230. b = m.TypeForHolderWithAddressOf.make()
  231. c = b
  232. assert b.get() is c.get()
  233. assert stats.alive() == 1
  234. del b
  235. assert stats.alive() == 1
  236. del c
  237. assert stats.alive() == 0
  238. def test_move_only_holder_with_addressof_operator():
  239. a = m.TypeForMoveOnlyHolderWithAddressOf.make()
  240. a.print_object()
  241. stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf)
  242. assert stats.alive() == 1
  243. a.value = 42
  244. assert a.value == 42
  245. del a
  246. assert stats.alive() == 0
  247. def test_smart_ptr_from_default():
  248. instance = m.HeldByDefaultHolder()
  249. with pytest.raises(RuntimeError) as excinfo:
  250. m.HeldByDefaultHolder.load_shared_ptr(instance)
  251. assert (
  252. "Unable to load a custom holder type from a "
  253. "default-holder instance" in str(excinfo.value)
  254. )
  255. def test_shared_ptr_gc():
  256. """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
  257. el = m.ElementList()
  258. for i in range(10):
  259. el.add(m.ElementA(i))
  260. pytest.gc_collect()
  261. for i, v in enumerate(el.get()):
  262. assert i == v.value()