Skip to content

Commit acd86f0

Browse files
Address #1138 when mixing holder_type's upon casting an object.
1 parent 04b41f0 commit acd86f0

File tree

2 files changed

+14
-4
lines changed

2 files changed

+14
-4
lines changed

include/pybind11/cast.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,12 @@ template <typename... Ts> class type_caster<std::tuple<Ts...>>
13671367
template <typename T>
13681368
struct holder_helper {
13691369
static auto get(const T &p) -> decltype(p.get()) { return p.get(); }
1370+
1371+
// Specialize move-only holder semantics to address #1138.
1372+
template <typename U = T>
1373+
static auto get(T &&p, enable_if_t<!is_copy_constructible<U>::value>* = nullptr) -> decltype(p.get()) {
1374+
return p.release();
1375+
}
13701376
};
13711377

13721378
/// Type caster for holder types like std::shared_ptr, etc.
@@ -1456,8 +1462,11 @@ struct move_only_holder_caster {
14561462
"Holder classes are only supported for custom types");
14571463

14581464
static handle cast(holder_type &&src, return_value_policy, handle) {
1459-
auto *ptr = holder_helper<holder_type>::get(src);
1460-
return type_caster_base<type>::cast_holder(ptr, &src);
1465+
// Move `src` so that `holder_helper<>::get()` can call `release` if need be.
1466+
// That way, if we mix `holder_type`s, we don't have to worry about `existing_holder`
1467+
// from being mistakenly reinterpret_cast'd to `shared_ptr<type>` (#1138).
1468+
auto *ptr = holder_helper<holder_type>::get(std::move(src));
1469+
return type_caster_base<type>::cast_holder(ptr, nullptr);
14611470
}
14621471
static constexpr auto name = type_caster_base<type>::name;
14631472
};

tests/test_smart_ptr.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ template <typename T> class huge_unique_ptr {
4040
uint64_t padding[10];
4141
public:
4242
huge_unique_ptr(T *p) : ptr(p) {};
43-
T *get() { return ptr.get(); }
43+
T *get() const { return ptr.get(); }
44+
T* release() { return ptr.release(); }
4445
};
4546
PYBIND11_DECLARE_HOLDER_TYPE(T, huge_unique_ptr<T>);
4647

@@ -51,7 +52,7 @@ class custom_unique_ptr {
5152
public:
5253
custom_unique_ptr(T* p) : impl(p) { }
5354
T* get() const { return impl.get(); }
54-
T* release_ptr() { return impl.release(); }
55+
T* release() { return impl.release(); }
5556
};
5657
PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
5758

0 commit comments

Comments
 (0)