Managing ref-counting is a complex and error prone business. If you choose C++ to extend or embed Python, you can simply use a modification on std::auto_ptr. Instead of calling delete on the managed pointer, it will decref it.
So now you can do:
auto_py str = PyStr_FromString("Hello World!");
and forget about having to decref it altogether! Just like auto_ptr you can get the PyObject * with get(), release it from managed control with release(), and rebind it with reset(new_ptr). You can also incref it by calling inc(), but be cautious as you can easily create a leak by increfing once to much.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <memory>
typedef std::auto_ptr<PyObject> auto_py_base;
class auto_py : public auto_py_base {
public:
auto_py(PyObject * obj = NULL) : auto_py_base(obj) {
}
~auto_py() {
reset();
}
void reset(PyObject * obj = NULL) {
if(obj != get()) {
PyObject * old = release(); // Avoid the delete call
Py_XDECREF(old);
auto_py_base::reset(obj);
}
}
void inc() {
PyObject * ptr = get();
if(ptr)
Py_INCREF(ptr);
}
};
|
You can do most of this with boost::python, but that library doesn't give you full access to the Python C API, so when you need to pass around PyObject pointers this comes in handy.
I've found this to be quite useful, and I created a fork of this recipe with some slight modifications. Mainly, implementing an operator overload for casting to
PyObject *
allows you to pass it to Python API functions without callingget()
every time (this seems like it might be slightly dangerous, but I haven't thought of any examples yet where it would be).