mirror of
https://github.com/pybind/pybind11.git
synced 2025-01-31 23:30:30 +00:00
Copying in shared_from_this_custom_deleters.cpp from github.com/rwgk, with adjustments.
Base version: e5318faa6a/shared_from_this_custom_deleters.cpp
This commit is contained in:
parent
28ed5ecce8
commit
4f00ffdc69
@ -1,10 +1,98 @@
|
|||||||
#include "pybind11_tests.h"
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
|
||||||
#include <pybind11/smart_holder.h>
|
#include <pybind11/smart_holder.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace shared_from_this_custom_deleters {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct labeled_delete {
|
||||||
|
std::string label;
|
||||||
|
explicit labeled_delete(const std::string &label) : label{label} {}
|
||||||
|
void operator()(T *raw_ptr) {
|
||||||
|
std::cout << "labeled_delete::operator() " << label << std::endl;
|
||||||
|
if (label != "SkipDelete") {
|
||||||
|
delete raw_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Atype : std::enable_shared_from_this<Atype> {};
|
||||||
|
|
||||||
|
#define SHOW_USE_COUNTS \
|
||||||
|
std::cout << "obj1, obj2 use_counts: " << obj1.use_count() << ", " << obj2.use_count() \
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
void obj1_owns() {
|
||||||
|
std::cout << "\nobj1_owns()" << std::endl;
|
||||||
|
std::shared_ptr<Atype> obj1(new Atype, labeled_delete<Atype>("1st"));
|
||||||
|
std::shared_ptr<Atype> obj2(obj1.get(), labeled_delete<Atype>("SkipDelete"));
|
||||||
|
SHOW_USE_COUNTS
|
||||||
|
auto sft1 = obj1->shared_from_this();
|
||||||
|
SHOW_USE_COUNTS
|
||||||
|
auto sft2 = obj2->shared_from_this();
|
||||||
|
SHOW_USE_COUNTS
|
||||||
|
}
|
||||||
|
|
||||||
|
void obj2_owns() {
|
||||||
|
std::cout << "\nobj2_owns()" << std::endl;
|
||||||
|
std::shared_ptr<Atype> obj1(new Atype, labeled_delete<Atype>("SkipDelete"));
|
||||||
|
std::shared_ptr<Atype> obj2(obj1.get(), labeled_delete<Atype>("2nd"));
|
||||||
|
SHOW_USE_COUNTS
|
||||||
|
auto sft1 = obj1->shared_from_this();
|
||||||
|
SHOW_USE_COUNTS
|
||||||
|
auto sft2 = obj2->shared_from_this();
|
||||||
|
SHOW_USE_COUNTS
|
||||||
|
}
|
||||||
|
|
||||||
|
void obj_sft_reset() {
|
||||||
|
std::cout << "\nobj_sft_reset()" << std::endl;
|
||||||
|
std::shared_ptr<Atype> obj1(new Atype, labeled_delete<Atype>("SkipDelete"));
|
||||||
|
std::shared_ptr<Atype> obj2(obj1.get(), labeled_delete<Atype>("ThisDeletes"));
|
||||||
|
std::shared_ptr<Atype> *obj_sft = nullptr;
|
||||||
|
std::shared_ptr<Atype> *obj_ign = nullptr;
|
||||||
|
{
|
||||||
|
auto sft1 = obj1->shared_from_this();
|
||||||
|
auto sft2 = obj2->shared_from_this();
|
||||||
|
long uc1 = obj1.use_count();
|
||||||
|
long uc2 = obj2.use_count();
|
||||||
|
if (uc1 == 3 && uc2 == 1) {
|
||||||
|
std::cout << "SHARED_FROM_THIS_REFERENT: 1" << std::endl;
|
||||||
|
obj_sft = &obj1;
|
||||||
|
obj_ign = &obj2;
|
||||||
|
} else if (uc1 == 1 && uc2 == 3) {
|
||||||
|
std::cout << "SHARED_FROM_THIS_REFERENT: 2" << std::endl;
|
||||||
|
obj_sft = &obj2;
|
||||||
|
obj_ign = &obj1;
|
||||||
|
} else {
|
||||||
|
std::cout << "SHARED_FROM_THIS_REFERENT: UNKNOWN" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (obj_sft == nullptr)
|
||||||
|
throw std::runtime_error("Unexpected `use_count`s.");
|
||||||
|
(*obj_sft).reset();
|
||||||
|
bool got_bad_weak_ptr = false;
|
||||||
|
try {
|
||||||
|
(*obj_ign)->shared_from_this();
|
||||||
|
} catch (const std::bad_weak_ptr &) {
|
||||||
|
got_bad_weak_ptr = true;
|
||||||
|
}
|
||||||
|
std::cout << "got_bad_weak_ptr: " << got_bad_weak_ptr << std::endl;
|
||||||
|
std::shared_ptr<Atype> obj3(obj2.get(), labeled_delete<Atype>("SkipDelete"));
|
||||||
|
// Working again based on the shared_ptr that was created after obj_sft was reset:
|
||||||
|
(*obj_ign)->shared_from_this();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace shared_from_this_custom_deleters
|
||||||
|
|
||||||
namespace test_class_sh_shared_from_this {
|
namespace test_class_sh_shared_from_this {
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
class MyObject3 : public std::enable_shared_from_this<MyObject3> {
|
class MyObject3 : public std::enable_shared_from_this<MyObject3> {
|
||||||
public:
|
public:
|
||||||
MyObject3(const MyObject3 &) = default;
|
MyObject3(const MyObject3 &) = default;
|
||||||
@ -35,6 +123,8 @@ struct SharedFromThisVBase : std::enable_shared_from_this<SharedFromThisVBase> {
|
|||||||
|
|
||||||
struct SharedFromThisVirt : virtual SharedFromThisVBase {};
|
struct SharedFromThisVirt : virtual SharedFromThisVBase {};
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
} // namespace test_class_sh_shared_from_this
|
} // namespace test_class_sh_shared_from_this
|
||||||
|
|
||||||
using namespace test_class_sh_shared_from_this;
|
using namespace test_class_sh_shared_from_this;
|
||||||
@ -45,6 +135,8 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(SharedFromThisRef)
|
|||||||
PYBIND11_SMART_HOLDER_TYPE_CASTERS(SharedFromThisVirt)
|
PYBIND11_SMART_HOLDER_TYPE_CASTERS(SharedFromThisVirt)
|
||||||
|
|
||||||
TEST_SUBMODULE(class_sh_shared_from_this, m) {
|
TEST_SUBMODULE(class_sh_shared_from_this, m) {
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
py::classh<MyObject3>(m, "MyObject3")
|
py::classh<MyObject3>(m, "MyObject3")
|
||||||
.def(py::init<int>());
|
.def(py::init<int>());
|
||||||
m.def("make_myobject3_1", []() { return new MyObject3(8); });
|
m.def("make_myobject3_1", []() { return new MyObject3(8); });
|
||||||
@ -71,4 +163,10 @@ TEST_SUBMODULE(class_sh_shared_from_this, m) {
|
|||||||
static std::shared_ptr<SharedFromThisVirt> sft(new SharedFromThisVirt());
|
static std::shared_ptr<SharedFromThisVirt> sft(new SharedFromThisVirt());
|
||||||
py::classh<SharedFromThisVirt>(m, "SharedFromThisVirt")
|
py::classh<SharedFromThisVirt>(m, "SharedFromThisVirt")
|
||||||
.def_static("get", []() { return sft.get(); }, py::return_value_policy::reference);
|
.def_static("get", []() { return sft.get(); }, py::return_value_policy::reference);
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
m.def("obj1_owns", shared_from_this_custom_deleters::obj1_owns);
|
||||||
|
m.def("obj2_owns", shared_from_this_custom_deleters::obj2_owns);
|
||||||
|
m.def("obj_sft_reset", shared_from_this_custom_deleters::obj_sft_reset);
|
||||||
}
|
}
|
||||||
|
@ -109,3 +109,15 @@ def test_shared_from_this_virt():
|
|||||||
z = m.SharedFromThisVirt.get()
|
z = m.SharedFromThisVirt.get()
|
||||||
y = m.SharedFromThisVirt.get()
|
y = m.SharedFromThisVirt.get()
|
||||||
assert y is z
|
assert y is z
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"test_func",
|
||||||
|
[
|
||||||
|
m.obj1_owns,
|
||||||
|
m.obj2_owns,
|
||||||
|
m.obj_sft_reset,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_shared_from_this_custom_deleters(test_func):
|
||||||
|
test_func()
|
||||||
|
Loading…
Reference in New Issue
Block a user