如何完成包含指针的lisp:struct?

时间:2018-08-05 15:56:54

标签: garbage-collection lisp common-lisp finalizer finalization

我正在将Lightweight Communications and Marshalling从julia移植到lisp,因为它具有更好的API。我使用swig来生成C函数调用。

我想知道这是否是C指针的安全用法。这是创建函数:

(defun create-lcm (&optional (provider (null-pointer)))
    (let* ((ptr (lcm_create provider))
           (addr (cffi:pointer-address ptr)))
        (tg:finalize ptr (lambda () (lcm_destroy (cffi:make-pointer addr))))
        (if (NULL-POINTER-P ptr)
                (error "lcm creation error"))
        (%create-lcm :pointer ptr :provider provider
                                 :file-descriptor (lcm_get_fileno ptr))))

问题:

  • 完成C指针的正确方法是什么?
  • 如何对此进行测试?

欢迎其他任何注释/建议。

谢谢。

2 个答案:

答案 0 :(得分:3)

有些错误的地方:

  1. 将终结器附加到可能为空的指针
  2. 我不确定您是否可以将终结器附加到外部指针。也许你是。
  3. 您需要谨慎对待终结器和gc。如果终结器引用了要终结的对象,则该对象与其终结器将彼此保持活动状态(由于终结器可能将对该对象的引用存储在某个地方,因此该对象将处于活动状态,因此不能一次收集它们,因此不应)还没有完成。

我不知道这是对的,但是更好:

(defun create-lcm (&optional (provider (null-pointer))
  (let ((ptr (lcm_create provider)))
    (when (null-pointer-p ptr)
      (error “lcm creation error”))
    (flet ((finaliser () (lcm_destroy ptr)))
      (let ((result (%create-lcm :pointer ptr :provider provider
                                 :file-descriptor (lcm_get_fileno ptr))))
        (tg:finalize result #'finaliser)
        result))))

有些错误的地方:

  1. 如果%create-lcmlcm_get_fileno出现错误,则终结器将无法运行

答案 1 :(得分:3)

您可能想了解有关cl-autowrap的知识,该知识特别用于将 SDL 2 包装在cl-sdl2中。该库提供了围绕指针的精简包装器,这些指针已经在完成时释放了内存。

我还认为,建议使用终结器的方法仅是使用它们来清理可能的泄漏,因为您几乎无法控制何时以及如何执行清理功能(例如,哪个线程,哪个动态环境)。 / p>

一种管理内存的方法是提前分配结构,并在不再需要它们时清理它们(池)。或者,您可以定义一个函数或宏来定义范围,以便使用unwind-protect在进入内存时分配内存并在退出时释放内存:

(defmacro with-lcm ((context &rest options) &body body)
  (let ((internal (gensym))) 
    `(let* ((,internal (create-lcm ,@options))
            (,context ,internal))
       (unwind-protect (progn ,@body)
         (destroy-lcm ,internal)))))