2016-01-31 2 views
0

Я ссылается этот SO ответ Does D have something akin to C++0x's move semantics?Имеет ли D конструктор перемещения?

Далее, вы можете переопределить конструктор C++ 's (конструктор & &, что), определив это (STRUCT что). Аналогично, вы можете переопределить назначение с помощью opAssign (Struct). В обоих случаях вам нужно убедиться, что вы уничтожаете значения этого.

Он приводит пример, как это:

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

Будет ли переменная thatвсегда перемещаются? Или может случиться так, что переменная that может быть скопирована в некоторых ситуациях?

Было бы несчастливо, если бы я только удалил ptr на временную копию.

ответ

4

Ну, вы также можете взглянуть на это так, вопрос:

Questions about postblit and move semantics

Путь, что структура копируется в D является то, что его память выведено, а затем, если он имеет конструктор postblit , его postblit-конструктор называется. И если компилятор определяет, что копия на самом деле не нужна, то она просто не вызывается конструктором postblit и не будет вызывать деструктор на исходном объекте. Таким образом, он перемещает объект, а не копирует его.

В частности, в соответствии с TDPL (с.251), язык гарантирует, что

  • Все анонимные rvalues ​​перемещаются, а не копируются. Вызов this(this) никогда не вставлен, когда источник является анонимным rvalue (т. Е. временным, как указано в функции hun выше).
  • Все названные временные ряды, которые выделены в стеке внутри функции, и , затем возвращаются на вызов this(this).
  • Нет никакой гарантии, что наблюдаются другие потенциальные нарушения.

Так, в других случаях компилятор может или не может игнорировать копии, в зависимости от текущей реализации компилятора и оптимизации уровня (например, если вы передаете именующее выражение для функции, которая принимает его по значению, и что переменная никогда не ссылается после вызова функции).

Так что, если у вас есть

void foo(Bar bar) 
{} 

то ли аргумент foo получает перемещен или не зависит от того, было ли это Rvalue или именующим. Если это значение rvalue, оно будет перемещено, тогда как если это значение lvalue, оно, вероятно, не будет (но может зависеть от кода вызова и компилятора).

Так что, если у вас есть

void foo(UniquePtr!T ptr) 
{} 

ptr будет перемещен, если foo был принят в RValue и может или не может быть перемещен его это прошло именующее выражение (хотя вообще нет). Итак, что происходит с внутренними компонентами UniquePtr, зависит от того, как вы его реализовали. Если UniquePtr отключил конструктор postblit, чтобы он не мог быть скопирован, то передача rvalue приведет к перемещению аргумента, и передача lvalue приведет к ошибке компиляции (поскольку гарантированно перемещение rvalue, тогда как lvalue - нет) ,

Теперь, что у вас есть

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

, который, кажется, действует как текущий тип имеет те же элементы, как те из его аргументов. Итак, я предполагаю, что то, что вы на самом деле пытаетесь сделать здесь, это конструктор конструктора копирования/перемещения для UniquePtr, а не конструктор для произвольного типа, который принимает UniquePtr!T. И если это то, что вы делаете, вам нужен конструктор postblit - this(this) - и не тот, который принимает тот же тип, что и сама структура (так как D не имеет конструкторов копирования). Так что, если то, что вы хотите, это конструктор копирования, то вы делаете что-то вроде

this(this) 
{ 
    // Do any deep copying you want here. e.g. 
    arr = arr.dup; 
} 

Но если побитовое копирование элементов вашей структуры работает для вашего типа, то вам не нужен конструктор postblit. Но перемещение является встроенным, поэтому вам необязательно объявлять конструктор перемещения независимо (перемещение будет просто разбивать элементы структуры). Скорее, если вы хотите гарантировать, что объект перемещен и никогда не копируется, то то, что вы хотите сделать, - это отключить конструктор postblit структуры. например

@disable this(this); 

Тогда любой и все время, что вы передаете UniquePtr!T в любом месте, он гарантированно будет двигаться или ошибка компиляции. И хотя я бы подумал, что вам, возможно, придется отключать opAssign отдельно, чтобы отключить присваивание, от внешнего вида (на основе кода, который я только что протестировал), вам даже не нужно отключать назначение отдельно. Отключение конструктора postblit также отключает оператор присваивания. Но если это не так, тогда вам просто нужно отключить opOpAssign.

+0

Я хотел бы отключить конструктор копирования, потому что мне нужно обеспечить уникальность, но мне все еще нужен конструктор перемещения, чтобы я мог обнулить значение ptr из rvalue. Afaik 'this (UniquePtr! T that)' является единственным синтаксисом для достижения этого. –

+0

Зачем вам нужно указывать указатель? Другого указателя на нуль нет. Объект был перемещен, поэтому есть только один объект, а не два. Тот, который вы хотите присвоить null, больше не существует.Единственный случай, когда я могу думать о том, где обнуление указателя имеет смысл, будет заключаться в том, что вы передавали право собственности между двумя значениями lvalues, которые были бы присвоением или копированием (хотя копирование на самом деле не позволяет это сделать, поскольку у вас нет доступа к оригинал в postblit, просто ссылки на те же данные для любых ссылочных типов элементов). В этом случае передача прав собственности должна, вероятно, быть ее собственной функцией. –

1

Думаю, я могу ответить на него сам. Цитирование «Язык программирования»:

Все анонимные значения перемещаются, а не копируются. Призыв к этому (это) никогда не вставлен , когда источник является анонимным значением rvalue (т. Е. Временным, как показано в функции hun выше).

Если я правильно понял это, это значит, что this(Struct that) никогда не будет копией, поскольку он принимает только значения rvalues.

+0

Мне кажется, что это не совсем то же самое, как двигаться строительство, и больше похожа на копию Elise Mechanic в C++, который также присутствовал перед движением конструкторов. – Cubic

3

JMD ответ охватывает теоретическую часть ходу семантики, я могу продлить его очень упрощенный пример реализации:

struct UniquePtr(T) 
{ 
    private T* ptr; 

    @disable this(this); 

    UniquePtr release() 
    { 
     scope(exit) this.ptr = null; 
     return UniquePtr(this.ptr); 
    } 
} 

// some function that takes argument by value: 
void foo (UniquePtr!int) { } 

auto p = UniquePtr!int(new int); 
// won't compile, postblit constructor is disabled 
foo(p); 
// ok, release() returns a new rvalue which is 
// guaranteed to be moved without copying 
foo(p.release()); 
// release also resets previous pointer: 
assert(p.ptr is null); 
Смежные вопросы