diff --git a/python/PyLogger.cxx b/python/PyLogger.cxx index 0437cd3e4..d9ce09bfb 100644 --- a/python/PyLogger.cxx +++ b/python/PyLogger.cxx @@ -41,7 +41,6 @@ PyLogger::PyLogger(PyObject* logger) { if (PyObject_IsInstance(logger, FGLogger_PyClass)) { logger_pyclass = logger; - Py_INCREF(logger_pyclass); } else { PyErr_SetString(PyExc_TypeError, "The logger must be an instance of FGLogger"); } @@ -50,7 +49,7 @@ PyLogger::PyLogger(PyObject* logger) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void PyLogger::SetLevel(LogLevel level) { - PyObject* py_level; + PyObjectPtr py_level; switch (level) { @@ -74,38 +73,33 @@ void PyLogger::SetLevel(LogLevel level) { break; } - bool success = CallPythonMethodWithArguments("set_level", py_level); - if (success) FGLogger::SetLevel(level); - Py_DECREF(py_level); + PyObjectPtr result = CallPythonMethodWithArguments("set_level", py_level); + if (result) FGLogger::SetLevel(level); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void PyLogger::FileLocation(const std::string& filename, int line) { - PyObject* py_filename = PyUnicode_FromString(filename.c_str()); - PyObject* py_line = PyLong_FromLong(line); - PyObject* args = PyTuple_Pack(2, py_filename, py_line); + PyObjectPtr py_filename = PyUnicode_FromString(filename.c_str()); + PyObjectPtr py_line = PyLong_FromLong(line); + PyObjectPtr args = PyTuple_Pack(2, py_filename.get(), py_line.get()); CallPythonMethodWithTuple("file_location", args); - Py_DECREF(args); - Py_DECREF(py_filename); - Py_DECREF(py_line); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void PyLogger::Message(const std::string& message) { - PyObject* msg = PyUnicode_FromString(message.c_str()); + PyObjectPtr msg = PyUnicode_FromString(message.c_str()); CallPythonMethodWithArguments("message", msg); - Py_DECREF(msg); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void PyLogger::Format(LogFormat format) { - PyObject* py_format; + PyObjectPtr py_format; switch (format) { @@ -142,35 +136,27 @@ void PyLogger::Format(LogFormat format) } CallPythonMethodWithArguments("format", py_format); - Py_DECREF(py_format); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool PyLogger::CallPythonMethodWithArguments(const char* method_name, PyObject* arg) +PyObjectPtr PyLogger::CallPythonMethodWithArguments(const char* method_name, const PyObjectPtr& arg) { - PyObject* tuple = PyTuple_Pack(1, arg); - bool success = CallPythonMethodWithTuple(method_name, tuple); - Py_DECREF(tuple); - return success; + PyObjectPtr tuple = PyTuple_Pack(1, arg.get()); + return CallPythonMethodWithTuple(method_name, tuple); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -bool PyLogger::CallPythonMethodWithTuple(const char* method_name, PyObject* tuple) +PyObjectPtr PyLogger::CallPythonMethodWithTuple(const char* method_name, const PyObjectPtr& tuple) { - PyObject* method = PyObject_GetAttrString(logger_pyclass, method_name); + PyObjectPtr method = PyObject_GetAttrString(logger_pyclass.get(), method_name); assert(method); // This should not fail as the constructor has checked the type of logger_pyclass. - PyObject* result = PyObject_CallObject(method, tuple); - Py_DECREF(method); + PyObjectPtr result = PyObject_CallObject(method.get(), tuple.get()); - if (result) { - Py_DECREF(result); - return true; - } + if (!result) PyErr_Print(); - PyErr_Print(); - return false; + return result; } } // namespace JSBSim diff --git a/python/PyLogger.h b/python/PyLogger.h index 4f5e50d7b..54ab6cedf 100644 --- a/python/PyLogger.h +++ b/python/PyLogger.h @@ -36,11 +36,65 @@ extern PyObject* FGLogger_PyClass; extern PyObject* LogLevel_PyClass; extern PyObject* LogFormat_PyClass; +// Helper class to manage the reference count of a PyObject. +class PyObjectPtr { +public: + PyObjectPtr(PyObject* obj = nullptr) noexcept + : object(obj) {} + + // Copy constructor + PyObjectPtr(const PyObjectPtr& other) noexcept { + object = other.object; + Py_XINCREF(object); + } + + // Move constructor + PyObjectPtr(PyObjectPtr&& other) noexcept + : object(other.object) + { + other.object = nullptr; + } + + // Copy assignment operator + PyObjectPtr& operator=(const PyObjectPtr& other) noexcept { + if (this != &other) { + Py_XDECREF(object); // Decrement the reference count of the current object + object = other.object; + Py_XINCREF(object); // Increment the reference count of the new object + } + return *this; + } + + PyObjectPtr& operator=(PyObject* src) noexcept { + Py_XDECREF(object); + object = src; + return *this; + } + + // Move assignment operator + PyObjectPtr& operator=(PyObjectPtr&& other) noexcept { + if (this != &other) { + Py_XDECREF(object); // Decrement the reference count of the current object + object = other.object; + other.object = nullptr; // Prevent the source from decrementing the reference count + } + return *this; + } + + ~PyObjectPtr() noexcept { Py_XDECREF(object); } + + PyObject* get() const noexcept { return object; } + operator bool() const noexcept { return object != nullptr; } + +protected: + PyObject* object; +}; + + class PyLogger : public FGLogger { public: explicit PyLogger(PyObject* logger); - ~PyLogger() override { Py_XDECREF(logger_pyclass); } void SetLevel(LogLevel level) override; void FileLocation(const std::string& filename, int line) override; void Message(const std::string& message) override; @@ -48,10 +102,10 @@ class PyLogger : public FGLogger void Flush(void) override { CallPythonMethodWithTuple("flush", nullptr); } private: - bool CallPythonMethodWithTuple(const char* method_name, PyObject* tuple); - bool CallPythonMethodWithArguments(const char* method_name, PyObject* arg); + PyObjectPtr CallPythonMethodWithTuple(const char* method_name, const PyObjectPtr& tuple); + PyObjectPtr CallPythonMethodWithArguments(const char* method_name, const PyObjectPtr& arg); - PyObject* logger_pyclass = nullptr; + PyObjectPtr logger_pyclass; }; } #endif