Вернуть экземпляр класса как указатель в D - PullRequest
3 голосов
/ 31 марта 2012

Я пытаюсь скомпилировать следующий код в D

void* instantiate(_LV2_Descriptor* descriptor, 
  double sample_rate, char * bundle_path, 
  LV2_Feature** features) {
  Plugin plugin = new Bleep(sample_rate, features);
  return &plugin;
}

но я получаю следующую ошибку

../src/lv2/plugin.d(38): Error: escaping reference to local plugin

Как правильно создать экземпляр класса и вернуть его в качестве указателя? Также таким образом, что это не заявлено GC. Существует еще один обратный вызов для удаления объекта.

Ответы [ 2 ]

4 голосов
/ 01 апреля 2012

Plugin и Bleep явно являются классами, поскольку вы присваиваете новую Bleep переменной Plugin, и в объявлении plugin нет *.Итак, plugin является ссылкой, а не указателем.&plugin возвращает указатель на ссылку - в данном случае это локальная переменная (отсюда и ошибка).Это совсем не то, что вы хотите.Вы можете явно привести plugin к void*, если вам действительно нужен указатель, но этот является несколько ненормальной вещью.Я предполагаю , что вы взаимодействуете с кодом C, иначе не должно быть оснований для приведения к void*.Объекты класса являются ссылками, а не указателями, и по возможности должны быть оставлены как таковые.Если вы передаете его в C-код (предположительно, который потом будет вызывать ваш D-код, поскольку C не знает, что делать с D-классом), то вы более или менее застряли, используя void*, но ясоветую избегать этого в противном случае.

GC не освободит объект, пока ваш код D имеет ссылку на него, но если вы передадите его функции C и не оставите ссылку наэто в вашем D-коде, это будет собираться в некоторый момент GC.

Если вы собираетесь явно освобождать объект самостоятельно, тогда не используйте GC.delete запланировано для устаревания, и вы обычно не должны освобождать вещи в куче GC самостоятельно.Это работа GC.Вы можете вызвать destroy для объекта, чтобы уничтожить его (например, destroy(obj);), но память не будет освобождена (скорее будет вызван деструктор, и vtable объекта будет обнулен, так что его использование приведет кsegfault).

Если вы действительно хотите выделять и освобождать объект самостоятельно, тогда вам следует использовать malloc и free, хотя это определенно сложнее.Вам нужно было бы выделить кусок памяти размером объекта с помощью malloc, а затем использовать std.conv.emplace, чтобы создать класс в этом фрагменте памяти для создания объекта.Затем, чтобы освободить его, вам придется явно вызвать его деструктор, а затем вызвать free в этой памяти.Работа выполняется над пользовательскими распределителями, которые определенно должны упростить эту задачу (возможно, значительно приблизив ее к alloc.new!MyClass(args) и alloc.free(obj)), но они еще не завершены и поэтому не находятся в стандартной библиотеке.

Один из способов справиться с выделением и освобождением объекта с помощью ГХ, если вам не нужно детерминированное уничтожение, - просто сохранить ссылку на объект в вашем D-коде, а затем установить эту ссылку на null, когда вы хотитеосвободить объект.Он не освободит его, пока GC не решит собрать его, но сделает так, чтобы GC не собирал его до того, как вы закончили с ним, и он сможет собрать его, как только вы это сделаете.

1 голос
/ 31 марта 2012

просто вернуть plugin это уже указатель

также, пока вы сохраняете ссылку на нее, GC

не будет требовать ее
...