В общем lisp, каков предпочтительный способ управления внешними ресурсами (сокеты, дескрипторы файловой системы и т.д.)?
Я пытаюсь сделать простой opengl 2d платформер общим lisp.
Проблема в том, что я не совсем уверен, как отслеживать текстуры OpenGL (необходимо удалить с помощью glDeleteTextures
, когда они больше не нужны).
В С++ я предпочел использовать следующую схему:
- Сделать класс текстур
- Сделать умные/слабые указатели для этого класса текстур
- Сохранять текстуры в карте (словарь/хэш-таблицу), которая сопоставляет имена файлов слабым указателям на текстуры.
- Когда запрашиваются новые текстуры, посмотрите на карту и посмотрите, есть ли нулевой (нулевой) слабый указатель. Если он доступен, верните существующий объект, иначе загрузите новую текстуру.
Однако я не совсем уверен, как перенести эту схему на общий lisp, потому что:
- Нет деструкторов.
- Там сборщик мусора, и кажется, что моя реализация (clozureCL на платформе Windows) поддерживает финализаторы, но, насколько я могу судить, не рекомендуется использовать финализаторы в общем lisp, потому что они не детерминированы.
- Предпочтительный способ управления ресурсами с помощью
(with-*
выглядит непригоден, потому что ресурсы могут использоваться совместно и загружаться/выгружаться в середине вызова функции.
Насколько я могу судить, существует несколько доступных подходов:
- Откажитесь от автоматического управления ресурсами и сделайте это вручную.
-
Внедрите что-то похожее на С++ RAII, слабый указатель и smartpointer с помощью макросов (этот код, вероятно, не работает):
(defclass destructible () ()) (defmethod destroy ((obj destructible)) (print (format nil "destroy: ~A" obj))) (defparameter *destructible-classes-list* nil) (defmethod initialize-instance :after ((obj destructible) &key) (progn (push *destructible-classes-list* obj) (print (format nil "init-instance: ~A" obj)))) (defmacro with-cleanup (&rest body) `(let ((*destructible-classes-list* nil)) (progn ,@body (mapcar (lambda (x) (destroy x)) *destructible-classes-list*)))) (defclass refdata (destructible) ((value :accessor refdata-value :initform nil) (ref :accessor refdata-ref :initform 0) (weakrefcount :accessor refdata-weakref :initform 0))) (defmethod incref ((ref refdata)) (if ref (incf (refdata-ref ref)))) (defmethod decref ((ref refdata)) (if ref (progn (decf (refdata-ref ref)) (if (<= (refdata-ref ref) 0) (progn (destroy (refdata-value ref)) (setf (refdata-value ref) nil)))))) (defmethod incweakref ((ref refdata)) (if ref (incf (refdata-weakref ref)))) (defmethod decweakref ((ref refdata)) (if ref (decf (refdata-weakref ref)))) (defclass refbase (destructible) ((data :accessor refbase-data :initform nil))) (defmethod deref ((ref refbase)) (if (and (refbase-data ref) (refdata-value (refbase-data ref))) (refdata-value (refbase-data ref)) nil)) (defclass strongref (refbase) ()) (defclass weakref (refbase) ()) (defmethod destroy :before ((obj strongref)) (decref (refbase-data obj))) (defmethod destroy :before ((obj weakref)) (decweakref (refbase-data obj))) (defmethod initialize-instance :after ((obj strongref) &key) (incref (refbase-data obj))) (defmethod initialize-instance :after ((obj weakref) &key) (incweakref (refbase-data obj)))
Есть ли лучший способ сделать это?
Концепции С++ Объяснение: Что такое умный указатель и когда я должен его использовать?