Есть ли в D что-то похожее на семантику перемещения C ++ 0x? - PullRequest
28 голосов
/ 17 ноября 2010

Проблема «типов значений» с внешними ресурсами (например, std::vector<T> или std::string) заключается в том, что их копирование обычно обходится довольно дорого, а копии создаются неявно в различных контекстах, поэтому это вызывает проблемы с производительностью. , Ответ C ++ 0x на эту проблему - семантика перемещения , которая концептуально основана на идее воровства ресурсов и технически основана на ссылочных значениях .

Есть ли в D что-то похожее на перемещение семантики или ссылок на значения?

Ответы [ 5 ]

25 голосов
/ 17 ноября 2010

Я считаю, что в D есть несколько мест (например, возвращающих структуры), в которых D удается заставить их двигаться, тогда как C ++ сделает их копию. IIRC, компилятор будет делать перемещение, а не копирование в любом случае, когда он может определить, что копия не нужна, поэтому структурное копирование в D будет происходить реже, чем в C ++. И, конечно, поскольку классы являются ссылками, у них вообще нет проблем.

Но независимо от того, конструкция копирования уже работает в D иначе, чем в C ++. Как правило, вместо объявления конструктора копирования вы объявляете конструктор postblit: this(this). Он выполняет полную memcpy до вызова this(this), и вы вносите только те изменения, которые необходимы, чтобы новая структура была отделена от оригинала (например, делала глубокую копию переменных-членов, где это необходимо), в отличие от создания совершенно новый конструктор, который должен копировать все Итак, общий подход уже немного отличается от C ++. Также общепризнанно, что структуры не должны иметь дорогих конструкторов с постблитом - копирование структур должно быть дешевым, так что это не такая большая проблема, как в C ++. Объекты, которые будут дорогостоящими для копирования, обычно являются либо классами, либо структурами со ссылкой или семантикой COW.

Контейнеры, как правило, являются ссылочными типами (в Фобосе они являются структурами, а не классами, так как им не нужен полиморфизм, но их копирование не копирует их содержимое, поэтому они все еще являются ссылочными типами), поэтому копируйте их не дорого, как это было бы в C ++.

В D вполне могут быть случаи, когда он мог бы использовать нечто похожее на конструктор перемещения, но в целом D был спроектирован таким образом, чтобы уменьшить проблемы, возникающие в C ++ при копировании объектов вокруг, так что это ни к чему рядом с проблемой, что это в C ++.

1 голос
/ 31 января 2016

Я думаю, что все ответы полностью не смогли ответить на первоначальный вопрос.

Во-первых, как указано выше, вопрос актуален только для структур. Классы не имеют никакого значимого движения. Также указано выше, что для структур при определенных условиях компилятором автоматически будет выполняться определенный объем.

Если вы хотите получить контроль над операциями перемещения, вот что вам нужно сделать. Вы можете отключить копирование, пометив это (это) с помощью @disable. Затем вы можете переопределить constructor(constructor &&that) в C ++, определив this(Struct that). Аналогично, вы можете переопределить присвоение с помощью opAssign(Struct that). В обоих случаях вам необходимо убедиться, что вы уничтожаете значения that.

Для назначения, поскольку вам также необходимо уничтожить старое значение this, самый простой способ - поменять их местами. Следовательно, реализация unique_ptr в C ++ будет выглядеть примерно так:

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: Обратите внимание, я не определил opAssign(ref UniquePtr!T that). Это оператор копирования, и если вы попытаетесь определить его, компилятор выдаст ошибку, потому что вы объявили в строке @disable, что у вас такого нет.

1 голос
/ 17 ноября 2010

Мне почему-то кажется, что на самом деле ссылки на rvalue и концепция «семантики перемещения» являются следствием того, что в C ++ нормально создавать локальные, «временные» объекты стека. В D и большинстве языков GC чаще всего объекты располагаются в куче, и при этом нет необходимости в том, чтобы временный объект копировался (или перемещался) несколько раз при возврате его через стек вызовов - так что есть нет необходимости в механизме, позволяющем избежать этих накладных расходов.

В D (и в большинстве языков GC) объект class никогда не копируется неявным образом, и вы просто передаете ссылку в большинстве случаев, так что может означать, что вам не нужно любые ссылки на них.

OTOH, struct объекты НЕ должны быть «дескрипторами к ресурсам», но простые типы значений ведут себя подобно встроенным типам - так что, опять же, здесь нет причин для какой-либо семантики перемещения, ИМХО.

Это дало бы заключение - D не имеет значений rvalue, потому что они не нужны .

Однако на практике я не использовал ссылки rvalue, я только прочитал их, поэтому я мог пропустить некоторые реальные случаи использования этой функции. Пожалуйста, отнеситесь к этому посту как к куче мыслей по этому вопросу, которые, надеюсь, будут полезны для вас, а не как к надежному суждению.

1 голос
/ 17 ноября 2010

D имеют отдельное значение и семантику объекта:

  • , если вы объявите свой тип как struct, он будет иметь значение семантическое по умолчанию
  • , если вы объявите свой тип как class, у него будет семантика объекта.

Теперь, предполагая, что вы не управляете памятью самостоятельно, поскольку это случай по умолчанию в D - при использовании сборщика мусора - вы должны понимать, что объекттипы, объявленные как class, автоматически указывают (или «ссылаются», если хотите) на реальный объект, а не на сам реальный объект.

Таким образом, при передаче векторов в D вы передаете ссылку/указатель.Автоматически.Никакая копия не используется (кроме копии ссылки).

Вот почему D, C #, Java и другие языки не «нуждаются» в перемещении семантики (так как большинство типов являются объектно-семантическими и обрабатываются ссылками,не копией).

Может быть, они могли бы реализовать это, я не уверен.Но действительно ли они получат повышение производительности, как в C ++?По природе это не кажется вероятным.

0 голосов
/ 17 ноября 2010

Я думаю, что если вам нужен источник, чтобы потерять ресурс, у вас могут быть проблемы. Однако, имея GC, вы часто можете не беспокоиться о нескольких владельцах, поэтому в большинстве случаев это может не быть проблемой.

...