在Haskell中调用对象删除时的函数

wrw*_*rwt 8 c++ garbage-collection haskell ffi

我正在为C++类编写Haskell包装器.我决定将它表示为一个Haskell数据结构,其中包含一个指向C++类实例的指针(Foreign.Ptr).这样的事情.

在C++中:

class MyClass {
public:
    double my_method();

    // ...
};

extern "C" MyClass* cpp_new_MyClass() {
    return new MyClass();
}

extern "C" double cpp_my_method(MyClass *obj) {
    return obj->my_method();
}
Run Code Online (Sandbox Code Playgroud)

在Haskell:

Data MyClass = MyClass (Ptr ())

foreign import ccall "cpp_new_MyClass" cppNewMyClass :: Ptr () 
foreign import ccall "cpp_my_method" cppMyMethod :: Ptr () -> Double

mkMyClass :: MyClass
mkMyClass = MyClass cppNewMyClass

myMethod :: MyClass -> Double
myMethod (MyClass ptr) = cppMyMethod ptr
Run Code Online (Sandbox Code Playgroud)

问题是,我不知道如何正确实现MyClass删除.在某些时候,Haskell垃圾收集器将删除MyClass对象,但它不会在C++中触发MyClass*内存释放.我该如何解决这个问题?

我知道ForeignPtr,但它使用IOmonad,这并不令人满意,因为我希望包装的数据结构与普通的Haskell数据结构完全相同,而不需要显式分配/释放内存或IOmonad.

lef*_*out 7

"它使用IOmonad,这并不令人满意,因为我希望包装数据结构的行为与普通的Haskell数据结构完全相同"

当然可以,但不幸的是,这不太可能.外部"函数"总是可以做有趣的事情,这在Haskell中是不可能的; 类型系统无法查看并阻止它.

这种困境是我们唯一的(!)原因unsafePerformIO,而且你的确是一个有效应用程序的好例子.

我自己还没有这样做,但你的代码看起来应该如下所示:

extern "C" void cpp_delete_MyClass(MyClass* obj) {
    delete obj;
}
Run Code Online (Sandbox Code Playgroud)
foreign import ccall "cpp_new_MyClass" cppNewMyClass :: IO (Ptr ())
foreign import ccall "&cpp_delete_MyClass" cppDeleteMyClass :: FunPtr (Ptr () -> IO ())

data MyClass = MyClass (ForeignPtr ())

mkMyClass :: MyClass
mkMyClass = unsafePerformIO $ do
   newObj <- cppNewMyClass
   fPtr <- newForeignPtr cppDeleteMyClass newObj
   return $ MyClass fptr
Run Code Online (Sandbox Code Playgroud)

我不太确定那些FunPtr,希望有人会对此发表评论......