Welcome, guest | Sign In | My Account | Store | Cart

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_pyptr pyHelloStr(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.

C++, 56 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
 * auto_pyptr.h
 *
 * Originally from
 * http://code.activestate.com/recipes/528875-automatic-ref-count-management-in-c-using-a-smart-/
 */

#ifndef AUTO_PYPTR_H_
#define AUTO_PYPTR_H_

#include <Python.h>
#include <memory>

typedef std::auto_ptr<PyObject> auto_pyptr_base;

/**
 * An auto_ptr that, instead of deleting, decrements the reference count
 * of a PyObject pointer.
 *
 * Make sure to only use this when you get a *new* reference (Py_INCREF or
 * getting the result of any function that says it returns a new reference
 * to a PyObject), NOT for "borrowed" references.
 */
class auto_pyptr : public auto_pyptr_base {
public:
    auto_pyptr(PyObject * obj = NULL) : auto_pyptr_base(obj) {
    }
    ~auto_pyptr() {
        reset();
    }
    void reset(PyObject * obj = NULL) {
        if(obj != get()) {
            PyObject * old = release(); // Avoid the delete call
            Py_XDECREF(old);
            auto_pyptr_base::reset(obj);
        }
    }
    void inc() {
        PyObject * ptr = get();
        if(ptr)
            Py_INCREF(ptr);
    }

    /*
     * Implement cast to PyObject pointer so you don't have to call var.get()
     * every time you use the object.
     *
     * You still have to use get() in certain cases, notably varargs
     * (i.e. "..."). GCC will warn you that this will abort at runtime.
     */
    operator PyObject*() {
        return this->get();
    }
};

#endif /* AUTO_PYPTR_H_ */

I forked this recipe to add a cast to PyObject *; this allows me to pass the pointer to other functions without calling get() every time.

If you think this is a bad idea for some reason (e.g. some way I'm likely to shoot myself in the foot), feel free to let me know.

Created by samh on Fri, 16 Dec 2011 (PSF)
C++ recipes (21)
samh's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks