diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index e45f1a0c67..628ff37e8f 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1069,7 +1069,7 @@ class class_ : public detail::generic_type { record.holder_size = sizeof(holder_type); record.init_instance = init_instance; record.dealloc = dealloc; - record.default_holder = std::is_same>::value; + record.default_holder = detail::is_instantiation::value; set_operator_new(&record); diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp index 098b1829b1..5f1fd07df4 100644 --- a/tests/test_smart_ptr.cpp +++ b/tests/test_smart_ptr.cpp @@ -186,6 +186,32 @@ TEST_SUBMODULE(smart_ptr, m) { .def(py::init()) .def_readwrite("value", &MyObject4::value); + // test_unique_deleter + // Object with std::unique_ptr where D is not matching the base class + // Object with a protected destructor + class MyObject4a { + public: + MyObject4a(int i) { + value = i; + print_created(this); + }; + int value; + protected: + virtual ~MyObject4a() { print_destroyed(this); } + }; + py::class_>(m, "MyObject4a") + .def(py::init()) + .def_readwrite("value", &MyObject4a::value); + + // Object derived but with public destructor and no Deleter in default holder + class MyObject4b : public MyObject4a { + public: + MyObject4b(int i) : MyObject4a(i) { print_created(this); } + ~MyObject4b() { print_destroyed(this); } + }; + py::class_(m, "MyObject4b") + .def(py::init()); + // test_large_holder class MyObject5 { // managed by huge_unique_ptr public: diff --git a/tests/test_smart_ptr.py b/tests/test_smart_ptr.py index 60f48b3982..72b1c2a16c 100644 --- a/tests/test_smart_ptr.py +++ b/tests/test_smart_ptr.py @@ -115,6 +115,27 @@ def test_unique_nodelete(): assert cstats.alive() == 1 # Leak, but that's intentional +def test_unique_nodelete4a(): + o = m.MyObject4a(23) + assert o.value == 23 + cstats = ConstructorStats.get(m.MyObject4a) + assert cstats.alive() == 1 + del o + assert cstats.alive() == 1 # Leak, but that's intentional + + +def test_unique_deleter(): + o = m.MyObject4b(23) + assert o.value == 23 + cstats4a = ConstructorStats.get(m.MyObject4a) + assert cstats4a.alive() == 2 # Two becaue of previous test + cstats4b = ConstructorStats.get(m.MyObject4b) + assert cstats4b.alive() == 1 + del o + assert cstats4a.alive() == 1 # Should now only be one leftover from previous test + assert cstats4b.alive() == 0 # Should be deleted + + def test_large_holder(): o = m.MyObject5(5) assert o.value == 5