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:
Ralf W. Grosse-Kunstleve 2021-06-10 07:17:32 -07:00 committed by Ralf W. Grosse-Kunstleve
parent 28ed5ecce8
commit 4f00ffdc69
2 changed files with 110 additions and 0 deletions

View File

@ -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);
} }

View File

@ -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()