Warum funktioniert das Dispose-Muster in C # nicht wie RAII in C ++?

8

Also habe ich gerade über das RAII Muster für nicht Müll-gesammelte Sprachen gelesen, und dies Abschnitt fiel mir ins Auge:

  

Diese Einschränkung tritt normalerweise auf, wenn benutzerdefinierte Klassen entwickelt werden. Benutzerdefinierte Klassen in C # und Java müssen die dispose-Methode explizit implementieren, um für den Client-Code verfügbar zu sein. Die dispose-Methode muss das explizite Schließen aller untergeordneten Ressourcen enthalten, die zur Klasse gehören. Diese Einschränkung existiert nicht in C ++ mit RAII, wo der Destruktor von benutzerdefinierten Klassen automatisch alle untergeordneten Ressourcen rekursiv zerstört, ohne dass expliziter Code erforderlich ist.

Warum kann C ++ diese Ressourcen, die im RAII-Muster zugewiesen sind, korrekt nachverfolgen, aber wir bekommen diesen schönen Stapel, der mit dem C # -Utiling-Konstrukt entwirrt, nicht?

    
BlackICE 29.08.2013, 14:38
quelle

4 Antworten

10

Angenommen, ein Objekt O besteht aus zwei Ressourcen besitzenden Objekten R und S. Was passiert, wenn O zerstört wird?

In C ++ mit RAII können Objekte andere Objekte besitzen, so dass die Zerstörung eines Objekts notwendigerweise mit den anderen Objekten gekoppelt ist. Wenn O Eigentümer von R und S ist - indem man sie nach Wert speichert oder etwas besitzt, das wiederum R und S besitzt (unique_ptr, Container, der R und S nach Wert speichert), dann muss notwendigerweise O zerstört werden Zerstört R und S. Solange die Destruktoren von R und S richtig aufräumen, muss O nichts manuell tun.

Im Gegensatz dazu haben C # -Objekte keinen Eigentümer, der entscheidet, wann seine Lebensdauer endet. Selbst wenn O deterministisch zerstört würde (was es im Allgemeinen nicht ist), könnten R und S durch eine andere Referenz erreichbar sein. Die Art und Weise, wie sich O auf R und S bezieht, ist dieselbe, wie jede andere lokale Variable, jedes Objektfeld, jedes Arrayelement usw. sich auf R und S bezieht. Mit anderen Worten, es gibt keine Möglichkeit, den Besitz anzugeben. t entscheiden, wann das Objekt vermeint zerstört werden soll und wann es nur eine nicht besitzende / geliehene Referenz war. Sicher würden Sie nicht erwarten, dass dieser Code die Datei schließt?

%Vor%

Aber soweit es die CLR betrifft, ist die Referenz von der lokalen f hier genau die gleiche wie die Referenz von O zu R / S.

TL; DR Eigentümer.

    
delnan 29.08.2013, 14:58
quelle
3

In C ++ haben Objekte bestimmte Lebensdauern. Die Lebensdauer von automatischen Variablen endet, wenn sie den Gültigkeitsbereich verlassen, und die Lebensdauern von dynamisch zugewiesenen Objekten enden, wenn sie gelöscht werden.

In C # werden die meisten Objekte dynamisch zugewiesen und es gibt keine Löschung. Daher haben Objekte keinen definierten Zeitpunkt, wann sie "gelöscht" werden. Das nächste, was Sie haben, ist using .

    
Chris Jester-Young 29.08.2013 14:43
quelle
2

Die kurze Antwort: Wann haben Sie zum letzten Mal Ihre eigenen Speicherzuweisungen / Ressourcenzuweisungen in einem Java / C # -Destruktor bereinigt? Wann haben Sie sich das letzte Mal daran erinnert, einen Java / C # Destruktor geschrieben zu haben?

Da Sie in C ++ für die Bereinigung verantwortlich sind, müssen Sie die Bereinigung vornehmen. Wenn Sie also aufhören, eine Ressource zu verwenden (wenn Sie einen guten Qualitätscode geschrieben haben), wird sie sofort bereinigt.

In verwalteten Sprachen ist der Garbage Collector für die Bereinigung zuständig. Eine Ressource, die Sie zugewiesen haben, könnte noch lange nach der Verwendung vorhanden sein (wenn der Garbage Collector schlecht implementiert ist). Dies ist ein Problem, wenn die verwalteten Objekte nicht verwaltete Ressourcen (z. B. Datenbankverbindungen) erstellen. Deshalb gibt es die Dispose -Methoden - um zu sagen, dass diese nicht verwalteten Ressourcen verschwinden. Da der Destruktor erst dann aufgerufen wird, wenn der Garbage Collector den Speicher aufräumt, würde die (endliche) Ressource durch die Bereinigung trotzdem länger geöffnet bleiben als nötig.

    
Zac Howland 29.08.2013 14:44
quelle
2

Um dies in C # korrekt zu implementieren, müssten Sie irgendwie markieren, welche Objekte der Klasse gehören und welche Objekte freigegeben sind. Vielleicht eine ähnliche Syntax wie diese:

%Vor%

Meine Vermutung ist, dass sie sich entschieden haben, diesen Weg nicht zu gehen, denn wenn Sie die Objekte, die Sie besitzen, markieren müssen, müssen Sie Code darüber schreiben. Und wenn Sie Code darüber schreiben müssen, können Sie es einfach in die Dispose -Methode schreiben und Dispose für die Objekte aufrufen, die Sie besitzen:)

In C ++ ist Objektbesitz normalerweise sehr klar - wenn Sie die Instanz selbst besitzen, besitzen Sie sie. In C # hältst du nie die Instanz selbst, du hältst immer eine Referenz, und eine Referenz kann etwas sein, das du besitzt oder etwas, das du benutzt - es gibt keine Möglichkeit zu sagen, welches ist True für eine bestimmte Instanz.

    
Alex 29.08.2013 14:52
quelle

Tags und Links