Use std::addressof to obtain holder address instead of operator&
diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp
index 61066f7..098b182 100644
--- a/tests/test_smart_ptr.cpp
+++ b/tests/test_smart_ptr.cpp
@@ -55,6 +55,35 @@
};
PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
+// 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;
+ 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"); }
+};
+PYBIND11_DECLARE_HOLDER_TYPE(T, shared_ptr_with_addressof_operator<T>);
+
+// 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;
+ 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"); }
+};
+PYBIND11_DECLARE_HOLDER_TYPE(T, unique_ptr_with_addressof_operator<T>);
+
TEST_SUBMODULE(smart_ptr, m) {
@@ -238,6 +267,41 @@
py::class_<C, custom_unique_ptr<C>>(m, "TypeWithMoveOnlyHolder")
.def_static("make", []() { return custom_unique_ptr<C>(new C); });
+ // test_holder_with_addressof_operator
+ struct TypeForHolderWithAddressOf {
+ TypeForHolderWithAddressOf() { print_created(this); }
+ TypeForHolderWithAddressOf(const TypeForHolderWithAddressOf &) { print_copy_created(this); }
+ TypeForHolderWithAddressOf(TypeForHolderWithAddressOf &&) { print_move_created(this); }
+ ~TypeForHolderWithAddressOf() { print_destroyed(this); }
+ std::string toString() const {
+ return "TypeForHolderWithAddressOf[" + std::to_string(value) + "]";
+ }
+ int value = 42;
+ };
+ 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()); })
+ .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
+ struct TypeForMoveOnlyHolderWithAddressOf {
+ TypeForMoveOnlyHolderWithAddressOf(int value) : value{value} { print_created(this); }
+ ~TypeForMoveOnlyHolderWithAddressOf() { print_destroyed(this); }
+ std::string toString() const {
+ return "MoveOnlyHolderWithAddressOf[" + std::to_string(value) + "]";
+ }
+ int value;
+ };
+ 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
struct HeldByDefaultHolder { };
py::class_<HeldByDefaultHolder>(m, "HeldByDefaultHolder")
diff --git a/tests/test_smart_ptr.py b/tests/test_smart_ptr.py
index 4dfe003..60f48b3 100644
--- a/tests/test_smart_ptr.py
+++ b/tests/test_smart_ptr.py
@@ -203,6 +203,50 @@
assert stats.alive() == 0
+def test_holder_with_addressof_operator():
+ # this test must not throw exception from c++
+ a = m.TypeForHolderWithAddressOf.make()
+ a.print_object_1()
+ a.print_object_2()
+ a.print_object_3()
+ a.print_object_4()
+
+ stats = ConstructorStats.get(m.TypeForHolderWithAddressOf)
+ assert stats.alive() == 1
+
+ np = m.TypeForHolderWithAddressOf.make()
+ assert stats.alive() == 2
+ del a
+ assert stats.alive() == 1
+ del np
+ assert stats.alive() == 0
+
+ b = m.TypeForHolderWithAddressOf.make()
+ c = b
+ assert b.get() is c.get()
+ assert stats.alive() == 1
+
+ del b
+ assert stats.alive() == 1
+
+ del c
+ assert stats.alive() == 0
+
+
+def test_move_only_holder_with_addressof_operator():
+ a = m.TypeForMoveOnlyHolderWithAddressOf.make()
+ a.print_object()
+
+ stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf)
+ assert stats.alive() == 1
+
+ a.value = 42
+ assert a.value == 42
+
+ del a
+ assert stats.alive() == 0
+
+
def test_smart_ptr_from_default():
instance = m.HeldByDefaultHolder()
with pytest.raises(RuntimeError) as excinfo: