Question

Un problème de « types de valeurs » avec des ressources externes (comme std::vector<T> ou std::string) est que les copiant a tendance à être assez coûteux, et des copies sont créées implicitement dans divers contextes, donc cela a tendance à être un problème de performance. La réponse de C ++ 0x à ce problème est sémantique déplacer , qui est conceptuellement basé sur l'idée de chapardage des ressources et alimenté techniquement par références rvalue .

D-t-il quelque chose semblable à déplacer la sémantique ou des références rvalue?

Était-ce utile?

La solution

Je crois qu'il ya plusieurs endroits dans D (comme struct retour) que D parvient à les faire se déplace alors C ++ serait en faire une copie. IIRC, le compilateur fera un mouvement plutôt qu'une copie dans tous les cas où il peut déterminer qu'une copie n'est pas nécessaire, la copie si struct va se passer moins en D que dans C ++. Et bien sûr, puisque les classes sont des références, ils n'ont pas le problème du tout.

Mais quelle que soit, la construction de copie fonctionne déjà différemment dans D que dans C ++. En général, au lieu de déclarer un constructeur de copie, vous déclarez un constructeur de postblit: this(this). Il fait un memcpy complet avant this(this) est appelé, et vous faire que tous les changements nécessaires pour faire en sorte que la nouvelle structure est séparée de l'original (comme faire une copie profonde des variables membres en cas de besoin), plutôt que de créer un tout nouveau constructeur qui doit copier tout. Ainsi, l'approche générale est déjà un peu différent de C ++. Il est également généralement convenu que struct ne devrait pas avoir des constructeurs coûteux postblit - struct copie devrait être pas cher - il est donc moins un problème que ce serait en C ++. Les objets qui seraient coûteux à copier sont généralement soit des classes ou struct avec la sémantique de référence ou VACHE.

Les conteneurs sont généralement référence types (dans Phobos, ils sont struct plutôt que des classes, car ils ne ont pas besoin polymorphisme, mais les copier ne copie pas leur contenu, ils sont donc encore référence types), afin de les copier autour est pas cher comme il serait en C ++.

Il peut très bien y avoir des cas dans D où il pourrait utiliser quelque chose de semblable à un constructeur de mouvement, mais en général, D a été conçu de telle manière à réduire les problèmes que C ++ a avec la copie d'objets autour, il est donc nulle part près du problème qu'il est en C ++.

Autres conseils

D ont une valeur séparée et la sémantique objet:

  • si vous déclarez votre type comme struct, il aura une valeur sémantique par défaut
  • si vous déclarez votre type comme class, il aura objet sémantique.

Maintenant, en supposant que vous gérez pas la mémoire vous-même, comme il est le cas par défaut dans D - au moyen d'un garbage collector - vous devez comprendre que l'objet de types déclarés class sont des pointeurs automatiquement (ou « référence » si vous préférez ) à l'objet réel, et non pas l'objet réel lui-même.

Ainsi, lors du passage des vecteurs autour de D, ce que vous passez est la référence / pointeur. Automatiquement. Aucune copie impliqué (autre que la copie de la référence).

Voilà pourquoi D, C #, Java et autres langues ne sont pas « besoin » en mouvement sémantique (comme la plupart des types sont l'objet sémantique et sont manipulés par référence, et non par copie).

Peut-être qu'ils pourraient mettre en œuvre, je ne suis pas sûr. Mais seraient-ils vraiment obtenir gain de performances comme en C ++? Par nature, il ne semble pas probable.

J'ai en quelque sorte le sentiment que fait les références rvalue et le concept de « déplacer sémantique » est une conséquence qu'il est normal en C ++ pour créer des objets locaux, pile « temporaires ». Dans D et la plupart des langues du GC, il est plus courant d'avoir des objets sur le tas, puis il n'y a pas de frais généraux d'avoir un objet temporaire copié (ou déplacé) à plusieurs reprises lors du retour à travers un appel pile - si il n'y a pas besoin d'un mécanisme pour éviter que les frais généraux trop.

Dans D (et la plupart des langues GC) un objet class n'est jamais copié implicitement et vous êtes seulement passer la référence dans la plupart du temps, donc ce peut signifie que vous n'avez pas besoin références rvalue pour eux.

OTOH, les objets ne sont pas censés struct être « poignées aux ressources », mais simples types de valeur similaire à un comportement builtin types -. Encore une fois, aucune raison pour que toute la sémantique de la déplacer, à mon humble avis

Cela donne une conclusion -. D n'a pas refs rvalue parce qu'il ne les ont pas besoin

Cependant, je ne l'ai pas utilisé les références rvalue dans la pratique, je n'ai eu une lecture sur eux, donc je pourrais avoir sauté certains cas d'utilisation réelle de cette fonction. S'il vous plaît traiter ce post comme un tas de réflexions sur la question qui nous l'espérons être utile pour vous, non pas comme un jugement fiable.

Je pense que toutes les réponses ont complètement échoué à répondre à la question initiale.

D'abord, comme indiqué ci-dessus, la question ne concerne struct. Les cours ont aucun mouvement significatif. En outre indiqué ci-dessus, pour struct, une certaine quantité de mouvement se fera automatiquement par le compilateur sous certaines conditions.

Si vous souhaitez obtenir le contrôle sur les opérations de déplacement, voici ce que vous avez à faire. Vous pouvez désactiver la copie en annotant ce (cette) avec @disable. Ensuite, vous pouvez remplacer constructor(constructor &&that) de C ++ en définissant this(Struct that). De même, vous pouvez remplacer le assign avec opAssign(Struct that). Dans les deux cas, vous devez vous assurer que vous détruire les valeurs de that.

Pour l'affectation, puisque vous avez aussi besoin de détruire l'ancienne valeur de this, la façon la plus simple est de les échanger. Une mise en œuvre de unique_ptr de C ++ serait donc ressembler à quelque chose comme ceci:

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: Remarquez que je ne définissaient pas opAssign(ref UniquePtr!T that). C'est l'opérateur d'affectation de copie, et si vous essayez de le définir, le compilateur erreur parce que vous avez déclaré, dans la ligne de @disable, que vous avez pas une telle chose.

Je pense que si vous avez besoin de la source de perdre la ressource que vous pourriez être en difficulté. Cependant, vous pouvez être GC'ed souvent éviter d'avoir à vous soucier de plusieurs propriétaires de sorte qu'il pourrait ne pas être un problème pour la plupart des cas.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top