Если я правильно понимаю, что постблитовый конструктор в D начинается с побитового копирования (всегда), то это определенное пользователем тело.
Но когда я смотрю на тело конструктора postblit, он очень похож на конструктор копирования C ++, единственное отличие состоит в том, что в C ++ источником является некоторый объект, а в D this
(сам).
Я прав?
Эх, близко. Я думаю, что у вас есть довольно хорошая ручка, но по буквам:
a = b;
(если a и b имеют одинаковый тип, структура) переводится в:
memcpy(&a, &b, b.sizeof); // bitwise copy
a.__postblit(); // call the postblit on the destination only (iff this(this) is defined on the type!)
Таким образом, вам не нужно явно назначать какие-либо переменные в постблите (они все копируются автоматически), а также нельзя использовать его для реализации семантики перемещения (у вас нет доступа к источнику).
Я чаще всего использую postblit, когда структура является указателем на другой объект, поэтому я могу увеличить refcount:
struct S {
SomeObject* wrapped;
this(this) { if(wrapped) wrapped.addReference(); }
~this() { if(wrapped) wrapped.releaseReference(); }
}
Это работает только со ссылками, так как в противном случае вы будете увеличивать копию переменной!
Вы Можно (но не следует) также использовать его для выполнения глубоких копий:
struct S {
string content;
this(this) { content = content.idup; }
}
Но на самом деле это плохая идея, поскольку назначение структуры должно быть универсально дешевым в D, а глубокие копии не дешевы. Как правило, в этом нет необходимости, так как сборщик мусора обрабатывает такие случаи, как double free, где вы могли бы захотеть этого в C ++.
Другой случай, когда я часто использую его в D, это его отключение:
struct S {
@disable this(this);
}
S a, b;
a = b; // compile error, b is not copyable
Это отличается от того, чтобы просто не реализовывать postblit, что оставляет вас с автоматической реализацией memcpy. Это делает присваивание явной ошибкой компиляции, которую вы можете использовать, чтобы направить пользователя к другому методу, например, для семантики перемещения:
struct S {
int* cool;
@disable this(this);
S release() { auto n = cool; cool = null; return S(cool); }
}
Поскольку a = b запрещено, теперь мы можем заставить пользователя использовать метод .release, когда он хочет переназначить его, что делает наше перемещение.
Других решений пока нет …