Frage

Ein Problem der „Wertetypen“ mit externen Ressourcen (wie std::vector<T> oder std::string) ist, dass sie zu kopieren neigt recht teuer zu sein, und Kopien werden implizit in verschiedenen Kontexten geschaffen, so dass diese Sorge eine Leistung zu sein tendiert. C ++ 0x Antwort auf dieses Problem ist Bewegung Semantik , die konzeptionell auf der Idee der Ressourcen pilfering basiert und technisch powered by rvalue Referenzen .

Does D haben etwas ähnliche Semantik oder rvalue Verweise bewegen?

War es hilfreich?

Lösung

Ich glaube, dass es mehrere Orte in D (wie Rückkehr structs), dass D verwaltet sie bewegt sich während C machen ++ würde sie eine Kopie machen. IIRC, wird der Compiler einen Schritt tun, anstatt eine Kopie in jedem Fall, in dem es, dass eine Kopie bestimmen kann, nicht benötigt wird, so struct Kopieren wird weniger passieren in D als in C ++. Und natürlich, da Klassen-Referenzen sind, sie haben nicht das Problem.

Aber egal, kopieren Bauarbeiten schon anders in D als in C ++. Im Allgemeinen stattdessen eine Kopie Konstruktor deklarieren, deklarieren Sie eine postblit Konstruktor: this(this). Es spielt eine vollständige Memcpy vor this(this) genannt wird, und Sie nur, was Änderungen sind notwendig, um sicherzustellen, dass die neue Struktur von den ursprünglichen getrennt ist (wie eine tiefe Kopie von Elementvariablen zu tun, wo erforderlich), im Gegensatz ein völlig neue Schaffung Konstruktor, der alles kopieren. So ist der allgemeine Ansatz schon ein bisschen anders als C ++. Es ist auch allgemein anerkannt, auf dass structs nicht teuer postblit Konstrukteure haben sollte - Kopieren structs sollte billig sein - so ist es weniger ein Problem ist, als es in C ++ wäre. Objekte, die teuer sein würden, sind entweder Klassen oder Strukturen mit Bezug oder COW Semantik im Allgemeinen zu kopieren.

Container sind in der Regel Referenztypen (in Phobos, sie sind structs statt Klassen, da sie Polymorphismus nicht brauchen, aber das Kopieren von ihnen kopiert nicht dessen Inhalt, so dass sie nach wie vor Referenztypen sind), so kopieren sie um ist nicht teuer, wie es in C ++ wäre.

Es kann sehr wohl Fälle in D sein, wo es etwas ähnlich wie bei einem Umzug Konstruktor verwenden könnte, aber im Allgemeinen haben D derart gestaltet, wie die Probleme zu verringern, dass C ++ hat mit Objekten um das Kopieren, so dass es nirgendwo ist in der Nähe von dem Problem, dass es in C ++.

Andere Tipps

D haben separate Wert und Objekt Semantik:

  • Wenn Sie Ihre Art als struct erklären, wird es Wert semantischen hat standardmäßig
  • Wenn Sie Ihre Art als class deklarieren, wird es Aufgabe semantische haben.

Nun, vorausgesetzt, Sie den Speicher selbst nicht verwalten, wie es der Standardfall in D ist - einen Müllsammler - muss man das Objekt der Typen verstehen erklärt als class automatisch Zeiger sind (oder „Referenz“, wenn Sie es vorziehen, ) auf das reale Objekt, nicht das reale Objekt selbst.

Also, wenn Vektoren um in D vorbei, was Sie passieren die Referenz / Zeiger. Automatisch. Keine Kopie beteiligt (anders als die Kopie der Referenz).

Deshalb D, C #, Java und andere Sprache nicht „müssen“ semantische bewegen (wie die meisten Objekttypen semantische sind und durch Bezugnahme manipulieren, nicht kopieren).

Vielleicht könnten sie es umsetzen, bin ich sicher nicht. Aber würde sie wirklich Leistungssteigerung wie in C ++ bekommen? Von Natur aus, scheint es nicht zu erwarten.

Ich habe irgendwie das Gefühl, dass tatsächlich die rvalue Referenzen und das gesamte Konzept der „move Semantik“ ist eine Folge, dass es normal ist in C ++ lokale „temporäre“ Stack-Objekte zu erstellen. In D und die meisten GC Sprachen, es sind am häufigsten Objekte auf dem Heap zu haben, und dann gibt es keinen Overhead mit einem temporären Objekt kopiert (oder verschoben) mehrmals, wenn es durch einen Aufruf der Rückkehr Stapel - so es gibt keine Notwendigkeit für einen Mechanismus zu vermeiden, die Overhead zu.

In D (und die meisten GC Sprachen) ein class Objekt wird niemals implizit kopiert und Sie vorbei nur die Referenz um die meiste Zeit, so dass diese können bedeutet, dass Sie nicht brauchen rvalue Referenzen für sie.

OTOH, struct Objekte sollen nicht „Griffe Ressourcen“ sein, aber einfache Werttypen verhalten ähnliche Typen builtin -. So wieder, keinen Grund für irgendwelche Bewegung Semantik hier IMHO

Dies würde eine Schlussfolgerung ergeben -. D hat nicht rvalue Refs, weil sie sie nicht benötigen

Allerdings habe ich nicht verwendet rvalue Referenzen in der Praxis habe ich nur gelesen auf sie hat, so dass ich einige Fälle tatsächliche Nutzung dieser Funktion übersprungen haben könnte. Bitte behandeln Sie diesen Beitrag als ein Bündel von Gedanken zu diesem Thema, die für Dich wäre hoffentlich hilfreich, nicht als zuverlässiges Urteil.

Ich denke, alle Antworten vollständig die ursprüngliche Frage gescheitert zu beantworten.

Zuerst wird, wie oben erwähnt, ist die Frage nur relevant für structs. Klassen haben keine sinnvolle Bewegung. Auch oben erwähnt, für structs, ein gewisses Maß an Bewegung automatisch durch den Compiler unter bestimmten Bedingungen passieren wird.

Wenn Sie die Kontrolle über die Bewegungsoperationen erhalten möchten, ist hier, was Sie zu tun haben. Sie können mit Anmerkungen versehen diese (this) mit @disable Kopieren deaktivieren. Als nächstes können Sie C ++ 's constructor(constructor &&that) außer Kraft setzen, indem this(Struct that) definieren. Ebenso können Sie die assign mit opAssign(Struct that) außer Kraft setzen. In beiden Fällen müssen Sie sicherstellen, dass Sie die Werte von that zerstören.

Für die Zuordnung, da man auch den alten Wert von this zerstören müssen, ist der einfachste Weg, um sie zu tauschen. Eine Implementierung von C ++ 's unique_ptr wäre daher in etwa so aussehen:

struct UniquePtr(T) {
    private T* ptr = null;

    @disable this(this); // This disables both copy construction and opAssign

    // The obvious constructor, destructor and accessor
    this(T* ptr) {
        if(ptr !is null)
            this.ptr = ptr;
    }

    ~this() {
        freeMemory(ptr);
    }

    inout(T)* get() inout {
        return ptr;
    }

    // Move operations
    this(UniquePtr!T that) {
        this.ptr = that.ptr;
        that.ptr = null;
    }

    ref UniquePtr!T opAssign(UniquePtr!T that) { // Notice no "ref" on "that"
        swap(this.ptr, that.ptr); // We change it anyways, because it's a temporary
        return this;
    }
}

Edit: Hinweis Ich habe definieren nicht opAssign(ref UniquePtr!T that). Das ist die Kopie Zuweisungsoperator, und wenn Sie versuchen, es zu definieren, werden Fehler der Compiler, weil Sie erklärt, in der @disable Linie, dass man so etwas nicht haben.

Ich denke, wenn Sie die Quelle benötigen die Ressource verlieren Sie in Schwierigkeiten sein könnten. Sie können oft vermeiden jedoch GC'ed ist über mehrere Eigentümer zu kümmern braucht, so dass es kein Problem für die meisten Fälle sein könnte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top