From 9564013c1d8d0afcc688d0e4701af85dae3001f6 Mon Sep 17 00:00:00 2001 From: ykiko Date: Wed, 28 Aug 2024 13:16:46 +0800 Subject: [PATCH] fix memory leak in property and staticmethod. (#301) * fix memory leak in property and staticmethod. * some format. --- include/pybind11/internal/function.h | 16 ++----- include/pybind11/tests/operators.cpp | 69 ++++++++++++++++++++++------ include/pybind11/tests/stl.cpp | 5 +- 3 files changed, 61 insertions(+), 29 deletions(-) diff --git a/include/pybind11/internal/function.h b/include/pybind11/internal/function.h index 934ea7a1..00dffa01 100644 --- a/include/pybind11/internal/function.h +++ b/include/pybind11/internal/function.h @@ -585,24 +585,14 @@ class cpp_function : public function { class property : public object { PKBIND_TYPE_IMPL(object, property, tp_property); - property(handle getter, handle setter = none()) : object() { - auto start = py_peek(0); - py_push(getter.ptr()); - py_push(setter.ptr()); - raise_call(type::of().index(), 2, start); - *this = object::from_ret(); - } + property(handle getter, handle setter = none()) : + object(type::of()(getter, setter)) {} }; class staticmethod : public object { PKBIND_TYPE_IMPL(object, staticmethod, tp_staticmethod); - staticmethod(handle method) : object() { - auto start = py_peek(0); - py_push(method.ptr()); - raise_call(type::of().index(), 1, start); - *this = object::from_ret(); - } + staticmethod(handle method) : object(type::of()(method)) {} }; namespace impl { diff --git a/include/pybind11/tests/operators.cpp b/include/pybind11/tests/operators.cpp index 378b0460..00a34155 100644 --- a/include/pybind11/tests/operators.cpp +++ b/include/pybind11/tests/operators.cpp @@ -1,5 +1,5 @@ #include "test.h" -#include +#include "pybind11/operators.h" namespace { @@ -8,19 +8,19 @@ struct Int { Int(int x) : x(x) {} -#define OPERATOR_IMPL(op) \ - template \ - friend int operator op (const LHS& lhs, const RHS& rhs) { \ - int l, r; \ - if constexpr(std::is_same_v) \ - l = lhs.x; \ - else \ - l = lhs; \ - if constexpr(std::is_same_v) \ - r = rhs.x; \ - else \ - r = rhs; \ - return l op r; \ +#define OPERATOR_IMPL(op) \ + template \ + friend int operator op (const LHS& lhs, const RHS& rhs) { \ + int l, r; \ + if constexpr(std::is_same_v) \ + l = lhs.x; \ + else \ + l = lhs; \ + if constexpr(std::is_same_v) \ + r = rhs.x; \ + else \ + r = rhs; \ + return l op r; \ } OPERATOR_IMPL(+) @@ -148,3 +148,44 @@ TEST_F(PYBIND11_TEST, logic_operators) { EXPECT_FALSE(a >= b); } +TEST_F(PYBIND11_TEST, item_operators) { + py::module_ m = py::module_::import("__main__"); + + py::class_>(m, "vector") + .def(py::init<>()) + .def("__getitem__", + [](std::vector& v, int i) { + return v[i]; + }) + .def("__setitem__", + [](std::vector& v, int i, int x) { + v[i] = x; + }) + .def("push_back", + [](std::vector& v, int x) { + v.push_back(x); + }) + .def("__str__", [](const std::vector& v) { + std::ostringstream os; + os << "["; + for(size_t i = 0; i < v.size(); i++) { + if(i > 0) os << ", "; + os << v[i]; + } + os << "]"; + return os.str(); + }); + + py::exec(R"( +v = vector() +v.push_back(1) +v.push_back(2) +v.push_back(3) +print(v) +assert v[0] == 1 +assert v[1] == 2 +assert v[2] == 3 +v[1] = 4 +assert v[1] == 4 +)"); +} diff --git a/include/pybind11/tests/stl.cpp b/include/pybind11/tests/stl.cpp index 33d8a886..dfff46cf 100644 --- a/include/pybind11/tests/stl.cpp +++ b/include/pybind11/tests/stl.cpp @@ -1,5 +1,5 @@ #include "test.h" -#include +#include "pybind11/stl.h" namespace { @@ -119,7 +119,8 @@ TEST_F(PYBIND11_TEST, dict_like) { py::object obj = py::cast(m); EXPECT_EVAL_EQ("{'a': Point(1, 2), 'b': Point(3, 4)}", obj); - std::unordered_map m2 = obj.cast>(); + std::unordered_map m2 = + obj.cast>(); EXPECT_EQ(m, m2); } }