2017-03-26 12 views
5

क्या वेक्टर की शुरुआत में कई तत्वों को निकालने का कोई अच्छा तरीका है?एक परिवर्तनीय वीईसी में पहले एन तत्वों को हटाने के लिए बेवकूफ तरीका क्या है?

मैं कई निष्कासन से बचना चाहता हूं जो अनावश्यक स्मृति प्रतिलिपि संचालन का कारण बनता है।

while vec.len() > n { 
    vec.remove(0); 
} 

  1. मैं असुरक्षित एपीआई (ptr::drop_in_place, ptr::copy, Vec::set_len), लेकिन वहाँ उम्मीद थी इस संभालने के लिए एक अधिक सुविधाजनक तरीका थे इस्तेमाल कर सकते हैं।

  2. एक वैकल्पिक समाधान संभव हो सकता है जहां Vec सूचक ऑफसेट हो गया है और शुरुआत में सीमा को निःशुल्क के रूप में चिह्नित किया गया है? (कोई स्मृति प्रतिलिपि की आवश्यकता नहीं है)। अब मुझे एहसास है कि इसके लिए रस्ट के अंतर्निहित आवंटक की आवश्यकता होती है जो प्रारंभिक रूप से आवंटित सूचक नहीं है, लेकिन यह पता चला है कि यह मामला नहीं है।

+0

ध्यान दें कि यह प्रश्न http://stackoverflow.com/questions/28952411 के समान है - केवल यह अंत के बजाय वेक्टर की शुरुआत के बारे में पूछता है। – ideasman42

उत्तर

11

उपयोग drain कई सन्निहित तत्वों संभव के रूप में एक ही बार में के रूप में कुशलता से एक वेक्टर से दूर करने के लिए (implementationptr::copy का उपयोग करता तत्वों है कि रहने के ले जाने के लिए):

let mut v = vec![1, 2, 3, 4]; 
v.drain(0..2); 
assert!(v == vec![3, 4]); 

# 2 के बारे में, यह है शेष तत्वों को स्थानांतरित करने से बचने के लिए व्यवहार्य नहीं है। उस अनुकूलन के लिए वेक्टर के प्रतिनिधित्व में परिवर्तन, आवंटकों में परिवर्तन, या दोनों के लिए परिवर्तन की आवश्यकता होगी, और सभी उपयोग के मामले में वेक्टर को कवर करने के लिए डिज़ाइन नहीं किया गया है। यदि आपको सामने से कुशल हटाने की आवश्यकता है, तो VecDeque का उपयोग करें।

Vec एक ट्रिपल < pointer-to-first-element, capacity, length > शामिल का प्रतिनिधित्व करती है। यदि आगे से हटाने से शेष सूचकों को प्रारंभ पॉइंटर आगे ले जाकर बचाया जाता है, तो डीलोकेशन क्रैश हो जाएगा क्योंकि स्टार्ट पॉइंटर अब आवंटक द्वारा प्रदान नहीं किया जाएगा। या तो वेक्टर को "मूल सूचक" के लिए एक नया क्षेत्र प्राप्त करने की आवश्यकता होगी, जो सभी वैक्टर ऑप्टिमाइज़ेशन के लिए भुगतान करेगा, या आवंटन इंटरफेस को ब्लॉक की शुरुआत को मुक्त करने के लिए एक विधि के साथ विस्तारित करने की आवश्यकता होगी। प्रत्येक फ्रंट हटाने को आवंटक में कॉल किया जाएगा, जिसमें निष्पादन के परिणाम होंगे जो मूल्यांकन करने में कठोर हैं, यह देखते हुए कि आवंटक को अपनी स्वयं की बहीखाता और संभवतः लॉक प्राप्त करना होगा। यह आवंटकों को बोझ भी जोड़ देगा, इसे मूल रूप से वितरित किए गए ब्लॉक से पहले इन संभावित छोटे अनलाइन किए गए मुक्त ब्लॉक का ट्रैक रखने की आवश्यकता होगी। यह वैक्टर को लगभग सभी मूल आवंटकों जैसे malloc() और mmap() के साथ असंगत बना देगा।

अंत में, अनुकूलन वर्तमान में Vec द्वारा प्रदान की गई गारंटीओं का खंडन करेगा। प्रलेखन explicitly states जो Vec को कम करने से इसकी क्षमता कम नहीं करेगा या इसे हटाएगा, जब तक कि shrink_to_fit पर कॉल न किया जाए। यह वेक्टरों के लिए अत्यधिक आवंटन से बचने के लिए है जो बहुत कम हो जाते हैं और बढ़ते हैं।

+0

धन्यवाद, मान लीजिए कि यह लगभग उतना ही कुशल है जितना कि ('ptr :: drop_in_place',' ptr :: copy', 'Vec :: set_len') – ideasman42

+0

@ ideasman42 यह निश्चित रूप से इरादा है - देखें [' ड्र्रेन के लिए ड्रॉप ड्रॉप ' ] (विवरण के लिए https://doc.rust-lang.org/src/collections/vec.rs.html#2120)। संकलक आशा करता है कि लूप में 'ptr :: drop_in_place' के समतुल्य लापता और छोड़े गए ऑब्जेक्ट्स को बनाने के लिए पर्याप्त स्मार्ट है, लेकिन यदि संदेह में है, तो यह जांचने के लिए उपाय करें कि यह आपके उपयोग के मामले के लिए काम करता है या नहीं। – user4815162342

+0

नोट: एक 'VecDeque' संगत भंडारण का उपयोग नहीं करता है (यह एक समान संगत बफर में संगत भंडारण के दो स्लाइसों का उपयोग करता है, लेकिन यह सी के साथ बातचीत के लिए पर्याप्त नहीं है)। –

1

यदि आप सीधे Vec का उपयोग करने के लिए नरक हैं, तो @user4815162342 समझाया गया है कि आप जो भी मांग रहे हैं वह असंभव है।

हालांकि, अगर (1) आपको वास्तव में सामने से प्रभावी हटाने की आवश्यकता है और (2) संगतता मायने रखती है ताकि VecDeque उचित नहीं है, तो अपने स्वयं के कंटेनर को बनाना भी संभव है। मैं एक बार उन (दो) सी ++ में कड़े आवश्यकताओं था, और सी ++ इस उदाहरण में जंग से ज्यादा कठिन है।

बुनियादी संरचना है:

struct DVec<T> { 
    data: *mut T, 
    length: usize, 
    offset: usize, 
    capacity: usize, 
    _marker: PhantomData<T>, 
} 

अपनी आवश्यकताओं के आधार पर, आप आम तौर पर आकार नीचे usize के स्थान पर u32 का उपयोग करके हटना कर सकते हैं (जो अभी भी 4 अरब तत्वों की अनुमति देता है!)।

उसके बाद, DVec::drain(..n) और DVec::drain(0..n)n द्वारा 0 बंपिंग द्वारा लागू किए गए हैं।

इस डेटा संरचना निम्न परिवर्तन के साथ एक अंतरफलक VecDeque के समान प्रदान करता है,: दोनों छोर पर एक तत्व की

  • प्रविष्टि

    • डेटा समीपवर्ती संग्रहीत किया जाता है, इस प्रकार यह Deref<Target = [T]> लागू करता है, है परिशोधित ओ (1),
    • किसी भी अंत में तत्व को हटाने ओ (1) है।

    सी ++ में, यह लिखना दर्दनाक है क्योंकि सभी ऑब्जेक्ट्स चलने योग्य नहीं हैं और चाल अपवाद का कारण बन सकती हैं; जंग में सभी वस्तुएं चलती हैं और चालें अपवाद मुक्त होती हैं, इसलिए यह काफी सरल है।

  • +0

    क्या आप वास्तव में उपयोगकर्ता पेज, या अन्य उत्तर से लिंक करना चाहते थे? – Shepmaster

    +0

    @ शेमपस्टर: उपयोगकर्ता पेज, कुछ उपयोगकर्ताओं को उपनाम बदलने की परेशान आदत है, इसलिए मैं उन्हें नीचे पिन करना पसंद करता हूं :) –

    +0

    लेकिन यदि आप उत्तर से लिंक करते हैं, तो यह हमेशा उस उत्तर के पोस्टर से जुड़ा होगा, भले ही नाम परिवर्तन यदि आपका उत्तर दूसरे उत्तर से ऊपर समाप्त होता है, तो दूसरे उत्तर का एक लिंक कूदने का एक आसान तरीका प्रदान करता है। – Shepmaster

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

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