Ungültige Zeigeroperationen beim Arbeiten mit Interfaces in Delphi

Wer in Delphi mit Interfaces arbeitet, ist sicher schon einmal in die Situation geraten, in der ein Mischbetrieb mit Objekt- und Interfacevariablen ungültige Zeigeroperationen ausgelöst haben. Wie man diesem Dilemma, zumindest bei Übergabeparametern an Methoden, aus dem Weg gehen kann, möchte ich kurz zeigen.

Was meine ich mit einem Mischbetrieb?

Als Beispiel hab ich ein einfaches Interface IFoo, welches die Methode Bar definiert.

Und ich habe eine Klasse TFoo, welche das Interface IFoo implementiert.

Nun kann ich die Klasse TFoo instanziieren und einer Variablen foo vom Typ TFoo zuweisen.

Soweit der einfache Fall.

Jetzt kommt aber einen Methode mit einem Übergabeparameter vom Typ IFoo ins Spiel.

Der Methode kann ich beim Aufrufen meine Objektvariable übergeben.

Das schluckt der Compiler und ich habe einen Mischbetrieb. Das heißt auf eine Objektinstanz wird einmal über eine Objektvariable (foo) und einmal über eine Interfacevariable (aFoo) zugegriffen.

Soweit kein Problem könnte man meinen. Könnte man 🙂

Automatische Freigabe von Objekten mit Referenzzähler

Erben von TInterfacedObject haben einen riesen Vorteil. Sie besitzen einen Referenzzähler, der die Instanz automatisch wieder frei gibt. Wird eine Instanz einer Interfacevariablen zugewiesen, so erhöht sich der interne Referenzzähler. Wird solch eine Variable wieder auf nil gesetzt oder wird der Gültigkeitsbereich dieser Variablen, z.B. eine Methode, verlassen, verringert sich der Referenzzähler um eins. Ist er beim Verringern bei 0 angekommen, so gibt sich das Objekt selber frei.

Prima Sache. Die Funktioniert leider nur, wenn Interfacevariablen und keine Objektvariablen genommen werden. Und genau da liegt das Dilemma.

Das Dilemma

In meinem Beispiel oben, erzeuge ich eine Instanz von TFoo und weise diese Instanz einer Objektvariablen foo zu. Diese Objektvariable wird nun in eine Methode als Übergabeparameter reingereicht. Diese Methode definiert die Übergabevariable aFoo aber als Interfacevariable.

Vor dem Aufrufen der Methode ist der Referenzzähler meines Objektes bei 0, da noch keine Interfacevariable auf die Instanz verweist. Rufe ich nun die Methode RufeBar auf, wird der Variablen aFoo die Instanz zugewiesen. Da es sich um eine Interfacevariable handelt, wird der interne Referenzzähler erhöht und auf 1 gesetzt.

Nun verlässt die Ausführung die Methode RufeBar und den Gültigkeitsbereich der Variablen aFoo. Dadurch wird der Referennzähler auf 0 verringert. Und eine Verringerung auf 0 ist das Zeichen für das Objekt, sich selber freizugeben.

Und schon zeigt in meiner aufrufenden Methode die Objektvariable foo auf einen nicht mehr gültigen Speicherbereich. Der nächste Zugriff oder der Versuch die Instanz freizugeben, werden mit einem Fehler scheitern.

Die Lösung

Die Lösung ist so simpel, dass ich lange überlegt habe, so ausführlich darüber zu schreiben. 🙂

Der Übergabeparameter der Methode RufeBar wird nicht als Variable, sondern als Konstante deklariert.

Damit löst aFoo in meinem Objekt keine automatische Referenzzählung mehr aus. Beim Verlassen der Methode wird die Instanz nicht freigegeben und kann außerhalb ganz normal weiterverwendet werden.

Auch eine Prima Sache 🙂

Ungültige Zeigeroperationen beim Arbeiten mit Interfaces in Delphi
Markiert in:

Ein Gedanke zu „Ungültige Zeigeroperationen beim Arbeiten mit Interfaces in Delphi

  • 3. September, 2012 um 14:51
    Permalink

    Super! Vielen Dank für diese ausführliche Erklärung und das Aufzeigen der Lösung für dieses Problem!
    Genau dieses Problem hatte mir grade Kopfzerbrechen bereitet!

    Antworten

Kommentar verfassen