Frage

Ich schreibe eine unveränderliche verknüpfte Liste Klasse in C, aber ein Verfahren ist auf mysteriöse Weise Speicherzugriffsfehler. Der Code soll in etwa entspricht dies sein:

class PList(object):
    def __init__(self, first, rest=None):
        self.first = first
        self.rest = rest

    def cons(self, item):
        return PList(item, self)

Hier ist mein Code:

#include <Python.h>
#include <structmember.h>

static PyTypeObject PListType;

typedef struct PListStruct{
  PyObject_HEAD
  PyObject *first;
  struct PListStruct *rest;
} PList;

static PyMemberDef plist_members[] = {
  {"first", T_OBJECT_EX, offsetof(PList, first), READONLY, "First element"},
  {"rest", T_OBJECT_EX, offsetof(PList, rest), READONLY, "Rest of the list"},
  {NULL}
};

static PyObject *
PList_cons(PList *self, PyObject *arg)
{
  PList *new_list = PyObject_CallFunctionObjArgs(&PListType, arg, self);
  Py_INCREF(new_list);
  return new_list;
}

static PyMethodDef plist_methods[] = {
  {"cons", (PyCFunction)PList_cons, METH_O, "Add an item to the list"},
  {NULL}
};


static void PList_dealloc(PList *self)
{
  Py_XDECREF(self->first);
  Py_XDECREF(self->rest);
  self->ob_type->tp_free((PyObject*)self);
}

static int
PList_init(PList *self, PyObject *args, PyObject *kwds)
{
  PyObject *first=NULL, *rest=NULL, *tmp;

  static char *kwlist[] = {"first", "rest", NULL};
  if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist,
                                    &first, &rest))
    return -1;

  if (first){
    tmp = self->first;
    Py_INCREF(first);
    self->first = first;
    Py_XDECREF(tmp);
  }

  if (rest) {
    tmp = self->rest;
    Py_INCREF(rest);
    self->rest = rest;
    Py_XDECREF(tmp);
  }
  else {
    tmp = self->rest;
    Py_INCREF(Py_None);
    self->rest = Py_None;
    Py_XDECREF(tmp);
  }

  return 0;
}

static PyTypeObject PListType= {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "pysistence.persistent_list.PList",             /*tp_name*/
    sizeof(PList), /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)PList_dealloc,                         /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,        /*tp_flags*/
    "Persistent list",           /* tp_doc */
    0,                       /* tp_traverse */
    0,                       /* tp_clear */
    0,                       /* tp_richcompare */
    0,                       /* tp_weaklistoffset */
    0,                       /* tp_iter */
    0,                       /* tp_iternext */
    plist_methods,          /* tp_methods */
    plist_members,                       /* tp_members */
    0,                       /* tp_getset */
    0,                       /* tp_base */
    0,                       /* tp_dict */
    0,                       /* tp_descr_get */
    0,                       /* tp_descr_set */
    0,                       /* tp_dictoffset */
    (initproc)PList_init,   /* tp_init */
    0,                       /* tp_alloc */
    0,                       /* tp_new */
};

#ifndef PyMODINIT_FUNC
#define PyMODINIT_FUNC void
#endif

PyMODINIT_FUNC
initpersistent_list(void)
{
  PyObject *m;

  PListType.tp_new = PyType_GenericNew;
  if (PyType_Ready(&PListType) < 0)
    return;

  m = Py_InitModule3("pysistence.persistent_list", 0,
                     "Docstring");
  Py_INCREF(&PListType);
  PyModule_AddObject(m, "PList", (PyObject*)&PListType);
}

Wenn ich diesen Code ausführen, es Segfaults in der letzten Zeile:

from pysistence.persistent_list import PList    

p = PList(1)
p = PList(2, p)
p = p.cons(3)

Ich bin sicher, ich mache nur etwas dumm, aber ich sehe nicht, was es ist. Gibt es etwas, was ich bin fehlt?

War es hilfreich?

Lösung

Ich bin aus der Dokumentation zu lesen:


PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ..., NULL)
    Return value: New reference.

Rufen Sie eine aufrufbare Objekt aufrufbar Python, mit einer variablen Anzahl von PyObject * Argumente. Die Argumente werden bereitgestellt, wie eine variable Anzahl von Parametern von NULL gefolgt. Gibt das Ergebnis des Aufrufs auf Erfolg oder NULL bei einem Fehler.


Sie werden am Ende den NULL-Wert fehlen.

Edit: Ho, und Sie wollen auch, wenn die Funktion zurückgibt NULL bei Speicherfehler

überprüfen
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top