2015-02-02 4 views
5

मैं जंग में एक पुस्तकालय लिख रहा हूं जिसमें सी इंटरफ़ेस है। सी पक्ष जंग की वस्तुओं को बनाने और नष्ट करने में सक्षम होना चाहिए (सी पक्ष उनका मालिक है और अपने जीवनकाल को नियंत्रित करता है)।मनमाने ढंग से जीवन भर के लिए सी कोड को जंग की वस्तु कैसे उधार देनी है?

मैं "रिसाव" को सेल्सियस के लिए एक वस्तु प्रबंधित किया है, लेकिन मुझे यकीन है कि कैसे करने के लिए ठीक से मुक्त यह नहीं कर रहा हूँ:

 
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??? 
} 

मुझे यकीन है कि मैं कैसे एक वस्तु को वापस सूचक बदल सकते हैं नहीं कर रहा हूँ कि जंग ड्रॉप पर कॉल करेगा। बस *handle संकलित नहीं करता है।

उत्तर

6

असल में, आप किसी ऑब्जेक्ट को सी को रिसाव करने में कामयाब रहे हैं; आप एक (शीघ्र) अस्तित्वहीन स्टैक फ्रेम के संदर्भ को रिसाव करने में कामयाब रहे हैं। : डी

यहाँ एक पूर्ण उदाहरण है कि सही ढंग से काम करना चाहिए। मैंने यह बताने के लिए उचित रूप से टिप्पणी करने की कोशिश की है कि मैं क्या कर रहा हूं और क्यों।

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())); 

    // * derefs the Box into a Dramatic, the &mut re-borrows it into a regular 
    // reference. The constraint ensures we coerce the &mut Dramatic into 
    // a *mut Dramatic, which "hides" the reference from the borrow checker. 
    let ptr: *mut _ = &mut *obj; 

    // Forget discards its argument (passed by-move), without trigger its 
    // destructor, if it has one. 
    ::std::mem::forget(obj); 

    ptr 
} 

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. 
    let obj: Box<Dramatic> = unsafe { ::std::mem::transmute(*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. 
    ::std::mem::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); 
} 
+3

'और म्यूट टी' से' * mut टी' को ट्रांसमिशन की आवश्यकता नहीं है; एक सरल 'as * mut _' करेगा। –

+2

असमानता क्यों? 'बनाना' एक '* म्यूट ड्रामैटिक 'देता है लेकिन' नष्ट 'एक' और mut * mut ड्रामैटिक 'लेता है जबकि सी में आप दोनों के लिए समान प्रकार के' नाटकीय * 'की अपेक्षा करेंगे। –

+3

@MatthieuM। "मैं' ptr' को बाहर निकालने जा रहा हूं, इसलिए कॉलिंग कोड गलती से सूचक का पुन: उपयोग करने की संभावना कम है "। यह एक सम्मेलन है जिसे मैंने सी में देखा है, लेकिन मुझे इसे कभी पसंद नहीं आया है। – Shepmaster

3

सेल्सियस के लिए एक जंग वस्तु भेजने के लिए:

 
#[no_mangle] 
pub extern "C" fn create_foo() -> *mut Foo { 
    Box::into_raw (Box::new(Foo)) 
} 

सी से उधार लिए (और नहीं मुक्त):

 
#[no_mangle] 
pub extern "C" fn do(foo: *mut Foo) -> *mut Foo { 
    let foo = foo. as_ref() .unwrap(); // That's ptr::as_ref 
} 

/अपने हाथ में लेने जंग वस्तु पहले से सी को दी नष्ट करने के :

संबंधित मुद्दे