У D есть что-то похожее на семантику C ++ 0x?
-
25-09-2019 - |
Вопрос
Проблема «типов ценностей» с внешними ресурсами (например, std::vector<T>
или std::string
) заключается в том, что копирование их имеет тенденцию быть достаточно дорогими, и копии создаются неявно в различных контекстах, поэтому это имеет тенденцию быть проблемой производительности. Ответ C ++ 0x на эту проблему Переместить семантику, который концептуально на основании идеи во врезании ресурсов и технически включенным Rvalue ссылки.
У d есть что-нибудь похожее на перемещение семантики или ссылок на рвале?
Решение
Я считаю, что в D (например, есть несколько мест в D (например, возвратные структуры), которые d удается сделать их перемещениями, тогда как C ++ сделает их копией. IIRC, компилятор будет делать ход, а не копию в любом случае, где она может определить, что копия не требуется, поэтому скопирование структуры произойдет меньше в D, чем в C ++. И, конечно же, поскольку классы - это ссылки, у них нет проблем вообще.
Но независимо от копирования конструкция уже работает по-разному в D, чем в C ++. Вообще, вместо того, чтобы объявлять Copy Constructor, вы объявляете постбит-конструктор: this(this)
. Отказ Это делает полный мемкпи до this(this)
Вызывается, и вы только делаете все возможные изменения, чтобы гарантировать, что новый структурь отделен от оригинала (например, делать глубокую копию переменных элементов, где это необходимо), в отличие от создания совершенно нового конструктора, который должен скопировать все. Итак, общий подход уже немного отличается от C ++. Также в целом согласовано эти структуры не должны иметь дорогих постбитных конструкторов - копирование структуров должно быть дешевым - так что это меньше проблем, чем в C ++. Объекты, которые были бы дорогими для копирования, обычно являются либо классами, либо структурами со ссылкой или семантикой COW.
Контейнеры, как правило, являются ссылочными типами (в фобосе, они строки, а не классы, поскольку они не нуждаются в полиморфизме, но копирование их не копирует их содержимое, поэтому они все еще ссылочные типы), поэтому копирование их не дорого Как будто это будет в C ++.
Там могут быть вполне могут быть случаи в D, где он мог использовать что-то похожее на конструктор движения, но в целом D был разработан таким образом, чтобы уменьшить проблемы, которые C ++ с копированием объектов вокруг, так что это никуда рядом с проблемой что это в C ++.
Другие советы
D имел отдельное значение и семантику объекта:
- Если вы объявите свой тип как
struct
, он будет иметь значение семантики по умолчанию - Если вы объявите свой тип как
class
, У него будет объект семантической.
Теперь, если предположить, что вы не управляете памятью самостоятельно, так как это случай по умолчанию в D - с помощью сборщика мусора - вы должны понимать, что объект типов объявлен как class
автоматически указатели (или «ссылка», если вы предпочитаете) к реальному объекту, а не сам реальный объект.
Итак, при прохождении векторов в D, то, что вы проходите, является эталонным / указателем. Автоматически. Нет копии (кроме копии ссылки).
Вот почему D, C #, Java и другой язык не «нуждаются в движущихся семантических условиях (поскольку большинство типов - это объект семантической и манипулируется посредством ссылки, а не копией).
Может быть, они могли бы реализовать это, я не уверен. Но бы они действительно получили повышение производительности, как в C ++? По природе, это не кажется вероятным.
Я каким-то образом у меня есть ощущение, что на самом деле ссылки на рвале и вся концепция «семантики движения» является следствием, что это нормально в C ++ для создания локальных «временных» объектов стека. В D и большинству языков Gc, наиболее распространенным, имеющим объекты на куче, а затем нет накладных расходов, имея временный объект, скопированный (или перемещаемый) несколько раз, когда возвращая его через стек вызова - Таким образом, нет необходимости в механизме, чтобы избежать этого накладных расходов.
В D (и большинство языках GC) class
объект никогда не копируется неявно, и вы проходите только в большую часть времени, так что это мая означает, что вам не нужны какие-либо ссылки на Rvalue для них.
ОТОЧ, struct
Объекты не должны быть «ручками к ресурсам», но простые типы значений ведут себя похоже на встроенные типы - так что еще раз, нет причин для любой семантики движения здесь, IMHO.
Это дало бы заключение - D не имеет RValue Refs, потому что они не нуждаются в.
Тем не менее, я не использовал ссылки на RVALUE на практике, у меня только было прочитать их, поэтому я мог бы пропустить некоторые фактические случаи использования этой функции. Пожалуйста, обратитесь к этому посту как куча мыслей по этому вопросу, который, надеюсь, будет полезен для вас, а не как надежное суждение.
Я думаю, что все ответы полностью не смогли ответить на оригинальный вопрос.
Во-первых, как указано выше, вопрос имеет отношение только к структурам. Классы не имеют значимого движения. Также указано выше, для структуру определенное количество хода произойдет автоматически с помощью компилятора при определенных условиях.
Если вы хотите получить контроль над операциями на ходу, вот что вы должны сделать. Вы можете отключить копирование, аннотируя это (это) с @disable. Далее вы можете переопределить C ++ constructor(constructor &&that)
определяя this(Struct that)
. Отказ Аналогично, вы можете переопределить назначение с opAssign(Struct that)
. Отказ В обоих случаях вам необходимо убедиться, что вы уничтожаете значения that
.
Для назначения, поскольку вам также нужно уничтожить старое значение this
, Самый простой способ - это поменять их. Внедрение C ++ unique_ptr
Поэтому будет выглядеть что-то вроде этого:
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;
}
}
Редактировать: Обратите внимание, что я не определял opAssign(ref UniquePtr!T that)
. Отказ Это оператор назначения копирования, и если вы попытаетесь его определить, компилятор ошибся, потому что вы объявили, в @disable
Линия, что у вас нет такой вещи.
Я думаю, что если вам нужен источник, чтобы потерять ресурс, вы можете быть в беде. Однако в том, что вы часто можете избежать необходимости беспокоиться о нескольких владельцах, поэтому он не может быть проблемой для большинства случаев.