2010-10-23 10 views
6

Ich lerne D, und bin verwirrt durch einen Fehler, den ich bekomme.Stack-basierte Objekt Instanziierung in D

Beachten Sie Folgendes:

module helloworld; 

import std.stdio; 
import std.perf; 

ptrdiff_t main(string[] args) 
{ 
    auto t = new PerformanceCounter; //From managed heap 
    //PerformanceCounter t;    //On the stack 

    t.start(); 
    writeln("Hello, ", size_t.sizeof * 8, "-bit world!"); 
    t.stop(); 

    writeln("Elapsed time: ", t.microseconds, " \xb5s."); 

    return 0; 
} //main() 

ergibt sich eine durchaus beachtliche:

Hello, 32-bit world! 
Elapsed time: 218 µs. 

Betrachten wir nun, was passiert, wenn ich versuche, Performance auf dem Stapel zu initialisieren, anstatt den verwalteten Heap verwenden:

//auto t = new PerformanceCounter; //From managed heap 
PerformanceCounter t;    //On the stack 

Ausbeuten:

--- killed by signal 10 

Ich bin ratlos. Irgendwelche Gedanken darüber, warum das bricht? (DMD 2.049 unter Mac OS X 10.6.4). Vielen Dank im Voraus für die Unterstützung eines n00b.

Antwort

5

Sie scheinen C++ - Klassen mit D-Klassen zu vermischen.

D-Klassen sind immer als Referenz übergeben (im Gegensatz zu, sagen wir, C++ Klassen) und PerformanceCounter t nicht die Klasse auf dem Stapel nicht vor, doch nur einen Zeiger darauf.

Das bedeutet, dass t auf null gesetzt ist, weil null der Standardinitialisierer für Zeiger ist - daher der Fehler.

EDIT: Sie können denken D Foo Klasse als C++ 's Foo*.

Wenn Sie möchten, dass dies auf dem Heap zugewiesen wird, können Sie stattdessen structs verwenden - sie können auch Methoden haben, genau wie Klassen. Sie haben jedoch keine Vererbung.

+0

Vielen Dank für den Hinweis !! :) (Das macht Sinn und beantwortet auch, warum das Objekt dereference/member operator (->) nicht benötigt wird. – anoncow

+0

Nun, der Operator -> wäre sowieso nicht erforderlich - zum Beispiel in C, der Compiler (wenn smart genug) kann Sie eigentlich warnen, dass Sie den falschen Operator verwenden In ähnlicher Weise brauchen D's Zeiger (sagen wir, Foo *) nicht ->, sondern arbeiten mit dem Punkt: 'Foo * foo = ; foo.bar = 5; ' –

+0

Entschuldigung, ich meinte, dass ich es nicht für das dynamisch zugewiesene Objekt benötige, nicht für das stackbasierte. – anoncow

1

Danke, Tim.

Dank Ihrer Antwort, ich war in der Lage die folgende an http://www.digitalmars.com/d/2.0/memory.html zu finden: auf dem Müll gesammelt Haufen


Zuweisen von Klasseninstanzen auf dem Stack

Klasseninstanzen werden in der Regel zugeordnet. Wenn sie jedoch: sind als lokale Symbole in einer Funktion zugewiesen sind mit neuen zugewiesen verwenden Sie neue ohne Argumente (Konstruktorargumente sind zulässig) haben Sie den Bereich Speicherklasse dann sind sie auf dem Stapel zugeordnet. Dies ist effizienter als ein Zuteilungs-/Freizyklus für die Instanz. Aber seien Sie vorsichtig, dass jede Bezugnahme auf das Objekt die Rückkehr der Funktion nicht überlebt.

class C { ... } 

scope c = new C(); // c is allocated on the stack 
scope c2 = new C(5); // allocated on stack 
scope c3 = new(5) C(); // allocated by a custom allocator 

Wenn die Klasse einen Destruktor hat, dann ist das destructor, wenn das Objekt geht, auch außerhalb des Bereichs der Klasse ausgeführt werden soll garantiert werden, wenn der Umfang über eine Ausnahme verlassen wird.


Mein Code liest jetzt

scope t = new PerformanceCounter(); //On the stack 

Diese (angeblich) ordnet auf dem Stapel und läuft gut. :)

Danke nochmal!

+2

Wie dsimcha in seinem Beitrag darauf hinweist, ist der Umfang jedoch für eine Abwertung geplant, also ist es keine gute langfristige Lösung. –

3

Die offensichtlichste Antwort ist die Verwendung eines struct. Wenn Sie eine Bibliothek verwenden, über die Sie keine Kontrolle haben, oder wenn die Heapzuweisungen ein Leistungsproblem darstellen, können Sie mithilfe der std.typecons.scoped-Funktionalität eine Klasseninstanz auf dem Stack unsicher zuweisen. Die Instanz wird weiterhin als Referenz übergeben, und wenn ihre Lebensdauer die Lebensdauer des aktuellen Stapelrahmens überschreitet, wird ein undefiniertes Verhalten die Folge sein. Das Schlüsselwort scope gemäß der Antwort von anoncow funktioniert, wird aber in D2 als veraltet eingestuft.

+0

Oh nein! Ich hatte mich gerade in den Bereich verliebt! Ich benutze D2, also werde ich nachlesen warum, das ist leider veraltet. Danke für den Strukturvorschlag - C++ 's Stapelzuweisungsmechanismus leidet unter dem gleichen Fehler. – anoncow

+0

Ich glaube, dass es im Wesentlichen veraltet ist, weil es unsicher ist. Wenn eine Klasse auf dem Stack vorhanden ist, besteht die Gefahr, dass ein Verweis darauf beibehalten wird, nachdem die Funktion zurückgegeben wurde und diese Referenz nicht mehr gültig ist. Wenn es auf dem Heap ist, wird es nicht Müll gesammelt werden, bis alle Verweise darauf verschwunden sind, so dass Sie dieses Problem nicht haben werden. –

+0

@anoncow: IIRC, ** Scope ** wird durch Bibliothekslösung ersetzt. Smth wie ** Scoped! (YourType) var ** –