3

我正在将轻量级通信和编组从 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 指针的正确方法是什么?
  • 如何为此进行测试?

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

提前致谢。

4

2 回答 2

3

以下是一些错误的事情:

  1. 将终结器附加到可能为空的指针
  2. 我不确定您是否可以将终结器附加到外部指针。也许你是。
  3. 你需要小心终结器和 gc。如果终结器引用它终结的对象,则对象及其终结器彼此保持活动状态(它们不能立即收集,因为终结器可能会在某处存储对该对象的引用,然后该对象将处于活动状态,因此应该t 已定稿。

我不知道这是否正确,但更好:

(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终结器将不会运行
于 2018-08-06T09:06:31.880 回答
3

您可能想阅读关于cl-autowrap,它主要用于将SDL 2包装 在cl-sdl2. 该库提供了围绕指针的瘦包装器,这些指针在完成时已经释放了内存。

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

管理内存的一种方法是提前分配结构并在不再需要它们时清理它们(池)。或者您可以定义一个函数或宏来定义一个范围,以便在进入时分配内存并在退出时释放,使用 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)))))
于 2018-08-06T09:43:04.430 回答