Freigeben von Ressourcen in D-Sprache

8

Wenn ich Direct3D in C ++ benutze, kann ich zum Beispiel eine "Cube" -Klasse schreiben, die einen "ID3D11Buffer * vertexBuffer_" enthält und sicherstellen, dass der Destruktor für dieses Cube-Objekt vertexBuffer _- & gt; Release () aufruft.

Ich kann eine "Scene" -Klasse haben, die ein "unique_ptr cube_" -Objekt enthält. Damit ich weiß, dass der Würfel gelöscht wird, wenn ich meine Szene lösche, und das wird folglich Release auf den D3D-Ressourcen aufrufen, die es verwendet.

In D kann ich das nicht machen. Ich kann Destruktoren schreiben, aber ich habe keine Ahnung, wann sie angerufen werden. Wenn der GC den Speicher nicht benötigt, darf er niemals aufgerufen werden ...

Was ist der beste Weg, um mit dieser Art von Dingen in D umzugehen? Ich könnte jedem Objekt eine "Free" -Mitgliedfunktion hinzufügen, die alle eigenen Ressourcen freigibt und bei beliebigen Objekten "Free" aufruft, aber dies scheint eine fehleranfällige manuelle Operation und ein Rückschritt von C ++ zu sein.

>

Gibt es einen besseren Weg, um mit dieser Art von Ding in D umzugehen?

    
jcoder 23.02.2012, 10:03
quelle

2 Antworten

6

Sie könnten eine Struktur auf dem Stapel verwenden. Das hat eine deterministische Zerstörung. Sie können es sogar mithilfe von std.typecons.RefCounted zurückzählen lassen. Verwenden Sie jedoch keine Struktur im Heap, wenn Sie sicherstellen möchten, dass der Destruktor ausgeführt wird. Im Moment denke ich nicht, dass Destruktoren von Strukturen jemals ausgeführt werden, wenn sie auf den Haufen geworfen werden, weil der GC nicht die Informationen hat, die er dazu benötigt (das sollte irgendwann in der Zukunft).

Wenn Sie jedoch darauf bestehen, den Heap in einer Klasse einzufügen und das Objekt explizit zu zerstören, können Sie clear darauf aufrufen:

%Vor%

Das wird den Destruktor des Objekts aufrufen und ihn dann in einen ungültigen Zustand setzen, und alles, was danach versucht, es zu benutzen, sollte explodieren (IIRC, die virtuelle Tabelle wird auf Null gesetzt). Aber die Erinnerung ist nicht wirklich freigegeben. Das ist die Aufgabe des GC. Und verwende nicht delete . Es wird veraltet sein. Ich bin wirklich überrascht, dass es noch nicht ist, da es seit Jahren geplant ist, es loszuwerden.

Und eine Option ist natürlich eine explizite Funktion, die Sie aufrufen, um die Ressourcen freizugeben. Ob das eine gute Idee ist oder nicht, hängt davon ab, was Sie tun. Aber unabhängig davon, Klassen sollen vom GC gesammelt werden und nicht freigegeben werden, wann immer Sie möchten.

Es wird an benutzerdefinierten Zuordnern gearbeitet, die Ihnen mehr Möglichkeiten für die Zuordnung einer Klasse geben würden, und eine davon würde wahrscheinlich eine deterministische Zerstörung von Klassen ermöglichen, aber das ist noch nicht fertig.

Und wenn Sie sich verrückt fühlen, können Sie std.typecons.scoped verwenden, das das bald ersetzt als veraltet gelten Modifizierer scope (obwohl scope in anderen Kontexten bleibt - wie scope -Anweisungen). Es legt eine Klasse auf den Stapel. Aber das ist unsicher (weshalb scope in diesem Zusammenhang weggeht), und Sie könnten wahrscheinlich auch nur eine Struktur verwenden, wenn Sie das Objekt auf den Stapel kleben.

BEARBEITEN: Sie könnten auch malloc und free mit std.conv.emplace , um das Objekt in einen nicht-GC zugewiesenen Speicherbereich zu legen, wie du es in C ++ tun würdest, aber ich denke, dass du den Destruktor explizit aufrufen musst, um ihn auszuführen, da free nichts über Destruktoren versteht (es ist eine C-Funktion). Das hätte den Vorteil, dass der Speicher zusammen mit der Ressource verschwindet (wohingegen die Verwendung von clear auf einem Objekt auf dem GC-Heap nur den Inhalt des Objekts zerstören, nicht den Speicher freigeben würde), aber ich weiß nicht, dass das kauft Sie verwenden clear für ein GC-allokiertes Objekt viel zu oft.

Sie könnten dann jedoch eine freie Funktion ähnlich wie new erstellen, die die malloc und emplace für Sie übernimmt, und dann eine freie Funktion ähnlich wie delete hat, die den Destruktor und free aufruft. Das würde Ihnen die gleiche Situation wie C ++ geben. In der Tat, ich frage mich, ob das nützlich genug wäre, um es in die Standardbibliothek zu bekommen. Das ist wahrscheinlich die Art von Sache, die in den benutzerdefinierten Allokatoren landen wird. Es würde mich also nicht überraschen, wenn Sie in naher Zukunft einen benutzerdefinierten Zuordner verwenden könnten, um etwas wie

zu tun %Vor%

Und ich würde denken, dass das Ihr Problem ziemlich gut lösen würde, da es im Wesentlichen dasselbe ist wie in C ++, nur mit Bibliotheksfunktionen und nicht mit den integrierten new und delete . Ich denke, dass ich es in der Newsgroup ansprechen werde. Ich erwarte, dass es zumindest einige Leute gibt, die solch ein Feature mögen, und das passt gut zu benutzerdefinierten Allokatoren.

    
Jonathan M Davis 23.02.2012, 11:18
quelle
2

Nur zur Klarstellung: Destruktoren werden immer aufgerufen. Wenn ein Objekt zum Zeitpunkt des Beendens der Anwendung noch nicht finalisiert wurde, wird der Finalizer vom GC ausgeführt.

Ich sehe nicht, wie das manuelle Aufrufen einer free () -Funktion zum Löschen des Vertex-Puffers fehleranfälliger ist als die manuelle Verwaltung des Speichers in C ++. Wie auch immer, Sie können sich folgendes anschauen: Ссылка und Ссылка

    
user438034 23.02.2012 10:09
quelle

Tags und Links