10

在 common lisp 中,管理外部资源(套接字、文件系统句柄等)的首选方法是什么?

我正在尝试用 common lisp 制作一个简单的 opengl 2d 平台游戏。问题是我不太确定如何跟踪 OpenGL 纹理(glDeleteTextures在不再需要它们时必须删除)。

在 C++ 中,我更喜欢使用以下方案:

  1. 制作纹理类
  2. 为该纹理类制作智能/弱指针
  3. 将纹理存储在将文件名映射到指向纹理的弱指针的映射(字典/哈希表)中。
  4. 当请求新的纹理时,查看地图,看看是否有可用的非空 (nil) 弱指针。如果可用,则返回现有对象,否则加载新纹理。

但是,我不太确定如何将此方案移植到 common lisp,因为:

  1. 没有析构函数。
  2. 有垃圾收集器,而且我的实现(Windows 平台上的 clozureCL)似乎支持终结器,但据我所知,不建议在 common lisp 中使用终结器,因为它们不是确定性的。
  3. 使用管理资源的首选方式在(with-*那里看起来不合适,因为资源可以共享,并在函数调用中间加载/卸载。

据我所知,有几种方法可用:

  1. 放弃自动资源管理,手动进行。
  2. 使用宏实现类似于 C++ RAII、weakpointer 和 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)))
    

有更好的方法吗?

C++ 概念说明: 什么是智能指针,什么时候应该使用它?

4

1 回答 1

9

如果要处理动态范围范围,请使用UNWIND-PROTECT。如果程序离开该范围 - 正常或出错 - 将调用清理表单。只需在那里解除分配或做任何你想做的事情。

有时 Lisps 使用某种“资源”机制来跟踪使用和未使用的对象。这样的库提供了从池中快速分配、分配、初始化、解除分配、资源对象的映射。CLIM 定义了一个原始版本:Resources。CCL 有一个类似的原始版本。

在带有“计时器”的 Lisp 中,您可以定期运行一个函数来查找要释放的“对象”。在 CCL 中,您可以使用休眠一段时间的线程PROCESS-WAIT

关于您的编码风格的一些信息:

  • FORMAT可以直接输出到流,不需要 PRINT
  • (defmethod foo ((e bar)) (if e ...)):IF没有意义。e将永远是一个对象。
  • 许多PROGN是不需要的。在需要时,可以在IF替换为 时将其删除WHEN
于 2012-11-10T20:58:23.033 回答