如何将Rust对象借给C代码一段任意寿命? [英] How to lend a Rust object to C code for an arbitrary lifetime?

查看:62
本文介绍了如何将Rust对象借给C代码一段任意寿命?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用Rust编写一个具有C接口的库. C端必须能够创建和销毁Rust对象(C端拥有它们并控制其寿命).

I'm writing a library in Rust that has a C interface. C side must be able to create and destroy Rust objects (C side owns them and controls their lifetime).

我设法将对象泄漏"到C,但是我不确定如何正确释放它:

I've managed to "leak" an object to C, but I'm not sure how to properly free it:


pub extern "C" fn create() -> *mut Foo {
   let obj = Foo; // oops, a bug
   let ptr = std::mem::transmute(&mut obj); // bad 
   std::mem::forget(obj); // not needed
   return ptr;
}

pub extern "C" fn destroy(handle: *mut Foo) {
   // get Foo back and Drop it??? 
}

我不确定如何将指针转回到Rust将调用Drop的对象上.简单地取消引用*handle不会编译.

I'm not sure how can I turn pointer back to an object that Rust will call Drop on. Simply dereferencing *handle doesn't compile.

推荐答案

实际上,您没有设法将对象泄漏给C.您设法泄漏了对(不久)不存在的堆栈框架的引用. :D

Actually, you haven't managed to leak an object to C; you've managed to leak a reference to a (shortly) non-existent stack frame. :D

这是一个完整的示例,应该可以正常工作.我已尝试对其进行适当评论,以解释我在做什么以及原因.

Here's a full example that should work correctly. I've tried to comment it as appropriate to explain what I'm doing and why.

pub struct Dramatic(String);

// Implement a destructor just so we can see when the object is destroyed.
impl Drop for Dramatic {
    fn drop(&mut self) {
        println!("And lo, I, {}, meet a most terrible fate!", self.0);
    }
}

pub extern "C" fn create() -> *mut Dramatic {
    // We **must** heap-allocate the object!  Returning a reference to a local
    // will **almost certainly** break your program!
    let mut obj = Box::new(Dramatic("Roger".to_string()));

    // into_raw turns the Box into a *mut Dramatic, which the borrow checker
    // ignores, without calling its destructor.
    Box::into_raw(obj)
}

pub extern "C" fn destroy(ptr: &mut *mut Dramatic) {
    // First, we **must** check to see if the pointer is null.
    if ptr.is_null() {
        // Do nothing.
        return;
    }

    // Now we know the pointer is non-null, we can continue. from_raw is the
    // inverse of into_raw: it turns the *mut Dramatic back into a
    // Box<Dramatic>. You must only call from_raw once per pointer.
    let obj: Box<Dramatic> = unsafe { Box::from_raw(*ptr) };

    // We don't *have* to do anything else; once obj goes out of scope, it will
    // be dropped.  I'm going to drop it explicitly, however, for clarity.
    drop(obj);

    // I am, however, going to null out the `ptr` we were passed just so the
    // calling code is less likely to accidentally re-use the pointer.
    *ptr = ::std::ptr::null_mut();
}

fn main() {
    let mut ptr = create();
    println!("ptr = {:?}", ptr);
    destroy(&mut ptr);
    println!("ptr = {:?}", ptr);
}

这篇关于如何将Rust对象借给C代码一段任意寿命?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆