Освобождение ресурсов на языке D - PullRequest
8 голосов
/ 23 февраля 2012

При использовании Direct3D в c ++ я могу написать, например, класс «Cube», который содержит «ID3D11Buffer * vertexBuffer_» и убедиться, что деструктор для этого объекта Cube вызывает vertexBuffer _-> Release ().

У меня может быть класс "Scene", содержащий объект "unique_ptr cube_".Так что я знаю, что когда я удаляю свою сцену, куб будет удален, и это, следовательно, вызовет освобождение ресурсов D3D, которые он использует.

В D я не могу этого сделать.Я могу писать деструкторы, но понятия не имею, когда они будут вызваны.Если ГХ не требует памяти, их никогда не могут называть ...

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

Есть ли лучший способ справиться с подобными вещами в D?

Ответы [ 2 ]

6 голосов
/ 23 февраля 2012

Вы можете использовать структуру в стеке. Это имеет детерминированное разрушение.Вы даже можете пересчитать его, используя std.typecons.RefCounting .Не используйте структуру в куче, если хотите гарантировать, что деструктор работает.На данный момент, я не думаю, что деструкторы структур когда-либо запускаются, если их помещают в кучу, потому что GC не имеет информации, которая ему необходима для этого (это должно быть исправлено в какой-то момент вхотя будущее).

Но если вы настаиваете на том, чтобы поместить его в кучу в классе, и хотите явно уничтожить объект, то вы можете вызвать clear для него:

clear(obj);

Это вызовет деструктор объекта, а затем переведет его в недопустимое состояние, и все, что попытается использовать его после этого, должно взорваться (IIRC, виртуальная таблица обнуляется).Но память на самом деле не освобождена.Это работа GC.И не используйте delete.Это будет устаревшим.Я на самом деле удивлен, что этого еще не было, так как было запланировано целую вечность, чтобы избавиться от него.

И, конечно, одним из вариантов является наличие явной функции, которую вы вызываете для освобождения ресурсов,Хорошая идея или нет, зависит от того, что вы делаете.Но независимо от того, классы предназначены для сбора GC и не освобождаются всякий раз, когда вы решите.

Работа выполняется на пользовательских распределителях, что даст вам больше возможностей для того, как распределить класс, и одиниз них, вероятно, вы сможете получить более детерминированное уничтожение классов, но это еще не готово.

А если вы чувствуете себя сумасшедшим, вы можете использовать std.typecons.scoped , которыйзаменяет устаревший модификатор типа scope (хотя scope остается в других контекстах - таких как операторы scope).Он помещает класс в стек.Но это небезопасно (именно поэтому scope уходит в этом контексте), и вы, вероятно, с таким же успехом можете просто использовать структуру, если вы собираетесь поместить объект в стек.

РЕДАКТИРОВАТЬ: Вы также можете использовать malloc и free с std.conv.emplace , чтобы поместить объект в выделенный кусок памяти без GC, как в C ++, ноЯ думаю, что вам придется явно вызывать деструктор, чтобы запустить его, так как free не понимает деструкторов (это C-функция).Это имело бы преимущество в том, что память уходила вместе с ресурсом (тогда как использование clear для объекта в куче ГХ просто уничтожило бы содержимое объекта, а не освободило память), но я не знаю, что это покупаетвы намного больше используете clear для объекта, выделенного GC.

Однако вы можете создать бесплатную функцию, аналогичную new, которая выполняет для вас malloc и emplace, и затем иметьбесплатная функция, похожая на delete, которая вызывает деструктор, и free, которая даст вам ту же ситуацию, что и C ++.На самом деле, мне интересно, будет ли это достаточно полезно, чтобы включить его в стандартную библиотеку.Это, вероятно, такая вещь, которая в конечном итоге в пользовательских распределителей, хотя.Поэтому меня совсем не удивит, если в относительно ближайшем будущем вы сможете использовать собственный распределитель для выполнения чего-то вроде

auto obj = customAllocObj.create!MyObj(args);
//Do stuff...
customAllocObj.destroy(obj);

И я думаю, что это решит вашу проблему довольно хорошо, учитывая, чтоПо сути, это то же самое, что и в C ++, только с библиотечными функциями, а не со встроенными new и delete.Я думаю, что я подниму это в группе новостей.Я ожидаю, что есть, по крайней мере, некоторые люди, которые хотели бы такую ​​функцию, и это, кажется, хорошо вписывается в пользовательские распределители.

2 голосов
/ 23 февраля 2012

Просто чтобы уточнить: деструкторы всегда вызываются. Если объект не был завершен к моменту закрытия приложения, GC запускает свой финализатор.

Я не вижу, как ручной вызов функции free () для удаления буфера вершин более подвержен ошибкам, чем необходимость вручную управлять памятью в C ++. В любом случае, вы можете посмотреть: http://www.dlang.org/phobos/std_typecons.html#scoped и http://www.dlang.org/phobos/std_typecons.html#RefCounted

...