test_unique_ptr_member.cpp 3.32 KB
Newer Older
1
2
#include "pybind11_tests.h"

3
4
#include <pybind11/vptr_holder.h>

5
#include <iostream>
6
7
8
9
10
#include <memory>

namespace pybind11_tests {
namespace unique_ptr_member {

11
12
inline void to_cout(std::string text) { std::cout << text << std::endl; }

13
14
15
16
class pointee { // NOT copyable.
  public:
    pointee() = default;

17
18
    int get_int() const {
        to_cout("pointee::get_int()");
19
        //TRIGGER_SEGSEV
20
21
22
23
        return 213;
    }

    ~pointee() { to_cout("~pointee()"); }
24
25
26
27
28
29
30
31

  private:
    pointee(const pointee &) = delete;
    pointee(pointee &&) = delete;
    pointee &operator=(const pointee &) = delete;
    pointee &operator=(pointee &&) = delete;
};

32
33
34
35
inline std::unique_ptr<pointee> make_unique_pointee() {
    return std::unique_ptr<pointee>(new pointee);
}

36
37
38
39
class ptr_owner {
  public:
    explicit ptr_owner(std::unique_ptr<pointee> ptr) : ptr_(std::move(ptr)) {}

40
41
42
43
44
45
46
47
48
    bool is_owner() const { return bool(ptr_); }

    std::unique_ptr<pointee> give_up_ownership_via_unique_ptr() {
        return std::move(ptr_);
    }
    std::shared_ptr<pointee> give_up_ownership_via_shared_ptr() {
        return std::move(ptr_);
    }

49
50
51
52
53
54
  private:
    std::unique_ptr<pointee> ptr_;
};

// Just to have a minimal example of a typical C++ pattern.
inline int cpp_pattern() {
55
56
57
    auto obj = make_unique_pointee();
    int result = (obj ? 1 : 8);
    obj->get_int();
58
    ptr_owner owner(std::move(obj));
59
60
61
62
63
64
65
66
67
68
    result = result * 10 + (obj ? 8 : 1);
    result = result * 10 + (owner.is_owner() ? 1 : 8);
    to_cout("before give up");
    auto reclaimed = owner.give_up_ownership_via_shared_ptr();
    to_cout("after give up");
    result = result * 10 + (owner.is_owner() ? 8 : 1);
    result = result * 10 + (reclaimed ? 1 : 8);
    reclaimed.reset();
    to_cout("after del");
    result = result * 10 + (reclaimed ? 8 : 1);
69
70
71
    return result;
}

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
} // namespace unique_ptr_member
} // namespace pybind11_tests

namespace pybind11 {
namespace detail {
template <>
struct type_caster<
    std::unique_ptr<pybind11_tests::unique_ptr_member::pointee>> {
  public:
    PYBIND11_TYPE_CASTER(
        std::unique_ptr<pybind11_tests::unique_ptr_member::pointee>,
        _("std::unique_ptr<pybind11_tests::unique_ptr_member::pointee>"));

    bool load(handle /* src */, bool) {
        throw std::runtime_error("Not implemented: load");
    }

    static handle
    cast(std::unique_ptr<pybind11_tests::unique_ptr_member::pointee> /* src */,
         return_value_policy /* policy */, handle /* parent */) {
        throw std::runtime_error("Not implemented: cast");
    }
};
} // namespace detail
} // namespace pybind11

namespace pybind11_tests {
namespace unique_ptr_member {

101
TEST_SUBMODULE(unique_ptr_member, m) {
102
    m.def("to_cout", to_cout);
103

104
    py::class_<pointee, py::vptr_holder<pointee>>(m, "pointee")
105
106
107
        .def(py::init<>())
        .def("get_int", &pointee::get_int);

108
109
    m.def("make_unique_pointee", make_unique_pointee);

110
    py::class_<ptr_owner>(m, "ptr_owner")
111
        .def(py::init<std::unique_ptr<pointee>>(), py::arg("ptr"))
112
113
114
115
116
117
118
        .def("is_owner", &ptr_owner::is_owner)
        .def("give_up_ownership_via_unique_ptr",
             &ptr_owner::give_up_ownership_via_unique_ptr)
        .def("give_up_ownership_via_shared_ptr",
             &ptr_owner::give_up_ownership_via_shared_ptr);

    m.def("cpp_pattern", cpp_pattern);
119
120
121
122
}

} // namespace unique_ptr_member
} // namespace pybind11_tests