如何最终确定 lisp:struct 包含一个指针?
How to finalize lisp:struct containing a pointer?
我正在移植 Lightweight Communications and Marshalling from julia to lisp as it has a better API. I used 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 指针的正确方法是什么?
- 如何进行测试?
欢迎任何其他 notes/advices。
提前致谢。
以下是一些错误的地方:
- 将终结器附加到可能为空的指针
- 我不确定是否允许将终结器附加到外部指针。也许你是。
- 您需要小心使用终结器和 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))))
这里有一些错误的地方:
- 如果
%create-lcm
或 lcm_get_fileno
出现错误,则终结器不会 运行
您可能想阅读有关 cl-autowrap
, which is used notably to wrap the SDL 2 in 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)))))
我正在移植 Lightweight Communications and Marshalling from julia to lisp as it has a better API. I used 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 指针的正确方法是什么?
- 如何进行测试?
欢迎任何其他 notes/advices。
提前致谢。
以下是一些错误的地方:
- 将终结器附加到可能为空的指针
- 我不确定是否允许将终结器附加到外部指针。也许你是。
- 您需要小心使用终结器和 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))))
这里有一些错误的地方:
- 如果
%create-lcm
或lcm_get_fileno
出现错误,则终结器不会 运行
您可能想阅读有关 cl-autowrap
, which is used notably to wrap the SDL 2 in 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)))))