When determining if a shared_ptr already exists, use a test on the we… (#2819)

* When determining if a shared_ptr already exists, use a test on the weak_ptr instead of a try/catch block.

* When determining if a shared_ptr already exists, use a test on the weak_ptr instead of a try/catch block.

* weak_from_this is only available in C++17 and later

* Switch to use feature flag instead of C++ version flag.

* Add Microsoft-specific check.

* Avoid undefined preprocessor macro warning treated as error.

* Simplify shared_from_this in init_holder

* Include <version> in detail/common.h (~stolen~ borrowed from @bstaletic's #2816)

* Move class_::get_shared_from_this to detail::try_get_shared_from_this

* Simplify try_get_shared_from_this by using weak_ptr::lock()

Co-authored-by: Yannick Jadoul <yannick.jadoul@belgacom.net>
This commit is contained in:
Edward Lockhart 2021-01-30 19:05:13 +00:00 committed by GitHub
parent 0432ae7c52
commit 23c3edcf21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 8 deletions

View File

@ -162,6 +162,11 @@
#include <memory>
#include <typeindex>
#include <type_traits>
#if defined(__has_include)
# if __has_include(<version>)
# include <version>
# endif
#endif
// #define PYBIND11_STR_LEGACY_PERMISSIVE
// If DEFINED, pybind11::str can hold PyUnicodeObject or PyBytesObject
@ -870,5 +875,23 @@ public:
// Forward-declaration; see detail/class.h
std::string get_fully_qualified_tp_name(PyTypeObject*);
template <typename T>
inline static std::shared_ptr<T> try_get_shared_from_this(std::enable_shared_from_this<T> *holder_value_ptr) {
// Pre C++17, this code path exploits undefined behavior, but is known to work on many platforms.
// Use at your own risk!
// See also https://en.cppreference.com/w/cpp/memory/enable_shared_from_this, and in particular
// the `std::shared_ptr<Good> gp1 = not_so_good.getptr();` and `try`-`catch` parts of the example.
#if defined(__cpp_lib_enable_shared_from_this) && (!defined(_MSC_VER) || _MSC_VER >= 1912)
return holder_value_ptr->weak_from_this().lock();
#else
try {
return holder_value_ptr->shared_from_this();
}
catch (const std::bad_weak_ptr &) {
return nullptr;
}
#endif
}
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -1505,14 +1505,13 @@ private:
template <typename T>
static void init_holder(detail::instance *inst, detail::value_and_holder &v_h,
const holder_type * /* unused */, const std::enable_shared_from_this<T> * /* dummy */) {
try {
auto sh = std::dynamic_pointer_cast<typename holder_type::element_type>(
v_h.value_ptr<type>()->shared_from_this());
if (sh) {
new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(sh));
v_h.set_holder_constructed();
}
} catch (const std::bad_weak_ptr &) {}
auto sh = std::dynamic_pointer_cast<typename holder_type::element_type>(
detail::try_get_shared_from_this(v_h.value_ptr<type>()));
if (sh) {
new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(sh));
v_h.set_holder_constructed();
}
if (!v_h.holder_constructed() && inst->owned) {
new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());