2015-05-20 13 views
23

जंग में, हम ढेर पर चीजों को आवंटित करने के लिए Box<T> प्रकार का उपयोग कर सकते हैं। इस प्रकार का उपयोग स्मृति को ढेर करने के लिए सुरक्षित रूप से अमूर्त पॉइंटर्स के लिए किया जाता है। Box<T> जंग मानक पुस्तकालय द्वारा प्रदान किया जाता है।बॉक्स कीवर्ड क्या करता है?

मैं उत्सुक था कि कैसे Box<T> आवंटन लागू किया गया है, इसलिए मुझे its source code मिला।

impl<T> Box<T> { 
    /// Allocates memory on the heap and then moves `x` into it. 
    /// [...] 
    #[stable(feature = "rust1", since = "1.0.0")] 
    #[inline(always)] 
    pub fn new(x: T) -> Box<T> { 
     box x 
    } 
} 

कार्यान्वयन में केवल लाइन मूल्य box x रिटर्न: यहाँ Box<T>::new के लिए कोड (जंग 1.0 के रूप में) है। यह box कीवर्ड आधिकारिक दस्तावेज़ीकरण में कहीं भी समझाया नहीं गया है; वास्तव में यह केवल std::boxed दस्तावेज़ीकरण पृष्ठ पर संक्षेप में उल्लेख किया गया है।

उत्तर

15

box x आमतौर पर आवंटित और मुक्त स्मृति के लिए उपयोग करता है?

उत्तर आवंटन के लिए लैंग आइटम exchange_malloc और exchange_free के लिए चिह्नित फ़ंक्शंस है। आप डिफ़ॉल्ट मानक लाइब्रेरी में heap.rs#L112 और heap.rs#L125 पर उन लोगों के कार्यान्वयन को देख सकते हैं।

अंत box x वाक्य रचना निम्नलिखित लैंग आइटम पर निर्भर करता है में:

  • owned_box एक Box struct पर आवंटित सूचक संपुटित करने के लिए। इस संरचना को Drop कार्यान्वयन की आवश्यकता नहीं है, इसे संकलक द्वारा स्वचालित रूप से कार्यान्वित किया जाता है।
  • exchange_malloc स्मृति आवंटित करने के लिए।
  • exchange_free पहले आवंटित स्मृति को मुक्त करने के लिए।

यह प्रभावी रूप से इस no_std उदाहरण का उपयोग जंग पुस्तक के lang items अध्याय में देखा जा सकता है:

#![feature(lang_items, box_syntax, start, no_std, libc)] 
#![no_std] 

extern crate libc; 

extern { 
    fn abort() -> !; 
} 

#[lang = "owned_box"] 
pub struct Box<T>(*mut T); 

#[lang = "exchange_malloc"] 
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { 
    let p = libc::malloc(size as libc::size_t) as *mut u8; 

    // malloc failed 
    if p as usize == 0 { 
     abort(); 
    } 

    p 
} 
#[lang = "exchange_free"] 
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { 
    libc::free(ptr as *mut libc::c_void) 
} 

#[start] 
fn main(argc: isize, argv: *const *const u8) -> isize { 
    let x = box 1; 

    0 
} 

#[lang = "stack_exhausted"] extern fn stack_exhausted() {} 
#[lang = "eh_personality"] extern fn eh_personality() {} 
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } 

सूचना कैसे DropBox struct के लिए लागू नहीं किया गया? खैर चलो LLVM आईआर main के लिए उत्पन्न देखें:

define internal i64 @_ZN4main20hbd13b522fdb5b7d4ebaE(i64, i8**) unnamed_addr #1 { 
entry-block: 
    %argc = alloca i64 
    %argv = alloca i8** 
    %x = alloca i32* 
    store i64 %0, i64* %argc, align 8 
    store i8** %1, i8*** %argv, align 8 
    %2 = call i8* @_ZN8allocate20hf9df30890c435d76naaE(i64 4, i64 4) 
    %3 = bitcast i8* %2 to i32* 
    store i32 1, i32* %3, align 4 
    store i32* %3, i32** %x, align 8 
    call void @"_ZN14Box$LT$i32$GT$9drop.103617h8817b938807fc41eE"(i32** %x) 
    ret i64 0 
} 

के रूप में निर्माण करने के लिए Box, इस बीच ... देखो उम्मीद allocate (_ZN8allocate20hf9df30890c435d76naaE) कहा जाता था! Box (_ZN14Box$LT$i32$GT$9drop.103617h8817b938807fc41eE) के लिए Drop विधि! चलो इस विधि के लिए आईआर देखें:

define internal void @"_ZN14Box$LT$i32$GT$9drop.103617h8817b938807fc41eE"(i32**) unnamed_addr #0 { 
entry-block: 
    %1 = load i32** %0 
    %2 = ptrtoint i32* %1 to i64 
    %3 = icmp ne i64 %2, 2097865
    br i1 %3, label %cond, label %next 

next:            ; preds = %cond, %entry- block 
    ret void 

cond:            ; preds = %entry-block 
    %4 = bitcast i32* %1 to i8* 
    call void @_ZN10deallocate20he2bff5e01707ad50VaaE(i8* %4, i64 4, i64 4) 
    br label %next 
} 

वहाँ यह है, deallocate (ZN10deallocate20he2bff5e01707ad50VaaE) उत्पन्न ड्रॉप संकलक पर बुलाया जा रहा है!

standard library पर भी नोटिस Drop विशेषता उपयोगकर्ता-कोड द्वारा लागू नहीं की गई है। वास्तव में एक जादुई संरचना का थोड़ा सा है।

10

box से पहले अस्थिर के रूप में चिह्नित किया गया था, इसे Box::new पर कॉल करने के लिए शॉर्टेंड के रूप में उपयोग किया गया था। हालांकि, यह हमेशा मनमाने ढंग से, Rc, या मनमाने ढंग से आवंटकों का उपयोग करने के लिए आवंटित करने में सक्षम होने का इरादा है। इनमें से कोई भी अंतिम रूप दिया गया है, इसलिए इसे 1.0 रिलीज़ के लिए स्थिर के रूप में चिह्नित नहीं किया गया था। यह जंग के सभी 1.x के लिए एक खराब निर्णय का समर्थन रोकने के लिए किया जाता है।

आगे के संदर्भ के लिए, आप RFC that changed the "placement new" syntax पढ़ सकते हैं और इसे भी गेटेड कर सकते हैं।

+0

तो वर्तमान में (ऊपर कार्यान्वयन में) 'बॉक्स x' प्लेसमेंट-नया वाक्यविन्यास है? – thirtythreeforty

+1

@thirtythreeforty, हाँ, यह प्लेसमेंट नया वाक्यविन्यास है जिसे वर्तमान में केवल 'बॉक्स' के साथ काम करने के लिए हार्डकोड किया गया है। –

+0

तो अंत में 'बॉक्स' का इलाज किसी भी प्रकार से विशेष रूप से नहीं किया जा सकता है, और यह केवल अन्य (पोस्ट-1.0) भाषा सुविधाओं का उपयोग करेगा। – thirtythreeforty

6

box वास्तव में Box::new() करता है - यह एक स्वामित्व वाला बॉक्स बनाता है।

मुझे विश्वास है कि आप box कीवर्ड के कार्यान्वयन क्योंकि वर्तमान में यह स्वामित्व बक्से के साथ काम करने के लिए hardcoded है नहीं मिल रहा है, और Box प्रकार एक लैंग आइटम है:

#[lang = "owned_box"] 
#[stable(feature = "rust1", since = "1.0.0")] 
#[fundamental] 
pub struct Box<T>(Unique<T>); 

क्योंकि यह एक लैंग मद है, कंपाइलर के पास इसके तत्कालता को संभालने के लिए विशेष तर्क है जो यह box कीवर्ड से लिंक कर सकता है।

मेरा मानना ​​है कि संकलक alloc::heap मॉड्यूल में कार्यों के लिए बॉक्स आवंटन प्रतिनिधि करता है।

box कीवर्ड के लिए सामान्य रूप से क्या करना है और सामान्य रूप से करना चाहिए, शेम्पास्टर का उत्तर पूरी तरह से वर्णन करता है।

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