[C-API] RefCount erhöhen bei Funktionsaufruf?

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
theliquidwave
User
Beiträge: 221
Registriert: Sonntag 1. Juni 2008, 09:08

Hallo,
mal in der Annahme, das es besser ist, einen neuen Thread auch bei kleinen Fragen zu erstellen, poste ich mal etwas mehr in dieser Sektion :)

Muss man den RefCount von Objekten, die man an ``PyObject_CallFunctionObjArgs`` und Konsorten übergibt, vorher erhöhen?
Ich _vermute_ nicht, da dazu nichts passendes in der Doku steht, aber bei so etwas wichtigem Frage ich lieber noch einmal nach.

Danke!
Grüßle.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Das mit den Refcounts in der C-API ist ein ziemliches Gewurschtel, aber man bekommt ein Gefühl dafür :-)

Mal angenommen, dass die augerufene Funktion keinen Müll baut mit den Refcounts der übergebenen Objekte, musst du den Refcount nicht erhöhen.

Bekommt eine Routine ein Objekt per Argument übergeben, hat diese ja eigentlich gar nicht die "Berechtigung", den Refcount zu vermindern, weil sie ja quasi nicht der Eigentümer (im Sinne von Ersteller) des Objektes ist. Das meinte ich mit "baut keinen Mist".

Ausnahmen sind natürlich Routinen die explizit Dinge löschen, wie z.B. 'PyDict_DelItem' (hieß doch so?). Und dann gibt es noch ein paar Routinen, die quasi Referenzen "stehlen", hab aber grad keine im Kopf.

Mit dieser kleinen Regel, also eine Routine vermindert den Refcount niemals implizit, wenn sie nicht "Eigentümer" des Objektes ist, schreibt man eigentlich ganz unwurschteligen Code. :-)
theliquidwave
User
Beiträge: 221
Registriert: Sonntag 1. Juni 2008, 09:08

Die Regel finde ich gut.
Eine dieser Funktionen ist PyList_SetItem. Ich habe auch lange genug gebraucht um diesen "Fehler" meinerseits zu finden :lol:

Danke!
Grüßle.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Welchen Sinn macht Referenzen-Stehlen überhaupt?
BlackJack

@Dauerbaustelle: Zeitersparnis weil man dann der Empfänger den Zähler nicht erhöht und der Aufrufer ihn nicht herunter zählen muss. Und semantisch gesehen überträgt man damit die Verantwortung für das Objekt dem Aufgerufenen.
theliquidwave
User
Beiträge: 221
Registriert: Sonntag 1. Juni 2008, 09:08

Schon, aber warum ist das nicht einheitlich? PyDict_SetItem stiehlt die Referenz beispielsweise nicht...

Gruß
Grüßle.
BlackJack

Keine Ahnung. Vielleicht historisch bedingt. Vielleicht hat auch irgendwer mal geschaut wo es am günstigsten ist. Denn das "stehlen" darf ja nur einmal pro Funktion passieren, wenn man nicht doch wieder den Referenzzähler anpassen will.
scoder
User
Beiträge: 13
Registriert: Freitag 4. Februar 2011, 19:04

Die korrekte Antwort auf diese Frage ist: Nein, wenn die Referenz dir gehört. Ja, wenn sie dir nicht gehört.

Zum Beispiel in dem Fall, dass du einen Aufrufparameter selbst auch nur aus einem dict oder einem Objektattribut genommen hast, gehört dir seine Referenz nicht automatisch. Wenn nun der Funktionsaufruf das Objekt verändert und die Referenz dabei herauslöscht, kann es plötzlich sein, dass sie ganz verschwindet und das Objekt gelöscht wird. -> Crash.

Also, einfache Regel: Immer sicherstellen, dass du eine Referenz hast, die dir auch wirklich gehört (oder sicherstellen, dass der Funktionsaufruf diesbezüglich sicher seiteneffektfrei ist *und* es auch in Zukunft bleibt!)

Ganz wichtig ist das beim Aufruf von C-Funktionen, aber bei Python-Funktionen kann das Problem auch entstehen, wenn der Funktionsaufruf kein Tupel/Dict für die Parameter erzeugt, in dem die Parameter gespeichert sind. Da du darauf meistens keinen Einfluss hast - lieber auf Nummer Sicher gehen.

Cython hatte übrigens auch schon mehr als einmal einen Bug in diesem Bereich, daher ist der generierte Code diesbezüglich inzwischen sehr gut getestet. Deshalb kann ich auch keinem empfehlen, solche Fehler in den eigenen C-Code einzubauen. Besser gleich Cython nehmen.
Antworten