"वसा सूचक" क्या है?


95

मैंने "वसा सूचक" शब्द को पहले से ही कई संदर्भों में पढ़ा है, लेकिन मुझे यकीन नहीं है कि वास्तव में इसका क्या अर्थ है और जब इसका उपयोग जंग में किया जाता है। पॉइंटर एक सामान्य पॉइंटर से दोगुना बड़ा लगता है, लेकिन मुझे समझ नहीं आता कि क्यों। यह भी लगता है कि विशेषता वस्तुओं के साथ कुछ करना है।


7
शब्द ही Rust-specific, BTW नहीं है। फैट पॉइंटर आमतौर पर एक पॉइंटर को संदर्भित करता है जो कुछ अतिरिक्त डेटा को स्टोर करता है इसके अलावा केवल ऑब्जेक्ट के पते को इंगित किया जा रहा है। यदि पॉइंटर में कुछ टैग बिट्स होते हैं और उन टैग बिट्स पर निर्भर करता है, तो पॉइंटर कभी-कभी पॉइंटर नहीं होता है, इसे टैगेड पॉइंटर प्रतिनिधित्व कहा जाता है । (जैसे कई स्मॉलटैक्स वीएम पर, 1 बिट के साथ समाप्त होने वाले पॉइंटर्स वास्तव में 31/63-बिट पूर्णांक होते हैं, क्योंकि संकेत शब्द-संरेखित होते हैं और इस प्रकार 1. कभी समाप्त नहीं होते हैं।) हॉटस्पॉट जेवीएम अपने वसा बिंदुओं को OOP कहता है (ऑब्जेक्ट-ओरिएंटेड) संकेत दिए गए)।
जॉर्ग डब्ल्यू मित्तग

2
बस एक सुझाव: जब मैं क्यू एंड ए जोड़ी पोस्ट करता हूं, तो मैं सामान्य रूप से एक छोटा नोट लिखता हूं जिसमें यह समझाया जाता है कि यह एक स्व-उत्तर वाला प्रश्न है, और मैंने इसे पोस्ट करने का फैसला क्यों किया। यहाँ प्रश्न में फुटनोट पर एक नज़र डालें: stackoverflow.com/q/46147231/5768908
Gerardo Furtado

@GerardoFurtado मैंने शुरू में एक टिप्पणी पोस्ट की थी जिसमें बताया गया था कि वास्तव में। लेकिन अब इसे हटा दिया गया (मेरे द्वारा नहीं)। लेकिन हां, मैं सहमत हूं, अक्सर ऐसा नोट उपयोगी होता है!
लुकास कालबर्टोड

@ जर्ग डब्ल्यू मित्तग 'साधारण वस्तु सूचक', वास्तव में
obataku

जवाबों:


110

शब्द "फैट पॉइंटर" का उपयोग संदर्भ और कच्चे पॉइंटर्स को गतिशील रूप से आकार (डीएसटी) - स्लाइस या विशेषता वस्तुओं को संदर्भित करने के लिए किया जाता है । एक फैट पॉइंटर में पॉइंटर प्लस कुछ जानकारी होती है जो DST को "पूर्ण" (जैसे लंबाई) बनाती है।

रस्ट में आमतौर पर उपयोग किए जाने वाले अधिकांश प्रकार डीएसटी नहीं हैं , लेकिन एक निश्चित आकार का संकलन समय पर जाना जाता है। ये प्रकार लक्षण को लागू करते हैंSized । यहां तक ​​कि प्रकार जो डायनेमिक आकार के ढेर बफर (जैसे Vec<T>) का प्रबंधन करते हैं, Sizedजैसे कि कंपाइलर जानता है कि बाइट्स की सटीक संख्या एक Vec<T>उदाहरण ढेर पर लग जाएगी। वर्तमान में Rust में चार अलग-अलग प्रकार के DST हैं।


स्लाइस ( [T]और str)

प्रकार [T](किसी के लिए T) गतिशील रूप से आकार है (इसलिए विशेष "स्ट्रिंग टुकड़ा" प्रकार है str)। इसलिए आप आमतौर पर इसे केवल एक संदर्भ के रूप में &[T]या &mut [T]अर्थात के रूप में देखते हैं । यह संदर्भ एक तथाकथित "वसा सूचक" है। चलो देखते है:

dbg!(size_of::<&u32>());
dbg!(size_of::<&[u32; 2]>());
dbg!(size_of::<&[u32]>());

यह प्रिंट (कुछ सफाई के साथ):

size_of::<&u32>()      = 8
size_of::<&[u32; 2]>() = 8
size_of::<&[u32]>()    = 16

तो हम देखते हैं कि सामान्य प्रकार u32का एक संदर्भ 8 बाइट्स जैसा है, जैसा कि एक सरणी के संदर्भ में है [u32; 2]। वे दो प्रकार डीएसटी नहीं हैं। लेकिन जैसा [u32]कि एक डीएसटी है, इसका संदर्भ दोगुना बड़ा है। स्लाइस के मामले में, DST को "पूरा" करने वाला अतिरिक्त डेटा केवल लंबाई है। तो कोई कह सकता है कि प्रतिनिधित्व &[u32]कुछ इस तरह है:

struct SliceRef { 
    ptr: *const u32, 
    len: usize,
}

विशेषता वस्तुओं ( dyn Trait)

ट्रिट ऑब्जेक्ट्स के रूप में ट्रिट का उपयोग करते समय (जैसे कि मिटाया गया, गतिशील रूप से भेजा गया), ये ट्रांजिट ऑब्जेक्ट डीएसटी हैं। उदाहरण:

trait Animal {
    fn speak(&self);
}

struct Cat;
impl Animal for Cat {
    fn speak(&self) {
        println!("meow");
    }
}

dbg!(size_of::<&Cat>());
dbg!(size_of::<&dyn Animal>());

यह प्रिंट (कुछ सफाई के साथ):

size_of::<&Cat>()        = 8
size_of::<&dyn Animal>() = 16

फिर से, &Catकेवल 8 बाइट्स बड़े हैं क्योंकि Catएक सामान्य प्रकार है। लेकिन dyn Animalएक विशेषता है और इसलिए गतिशील रूप से आकार। जैसे, &dyn Animal16 बाइट्स बड़ी है।

विशेषता वस्तुओं के मामले में, DST को पूरा करने वाला अतिरिक्त डेटा vtable (vptr) के लिए एक संकेतक है। मैं पूरी तरह से यहाँ vtables और vptrs की अवधारणा की व्याख्या नहीं कर सकता, लेकिन वे इस आभासी प्रेषण संदर्भ में सही विधि कार्यान्वयन को कॉल करने के लिए उपयोग किए जाते हैं। वीआईबीटी डेटा का एक स्थिर टुकड़ा है जिसमें मूल रूप से प्रत्येक विधि के लिए केवल फ़ंक्शन पॉइंटर होता है। इसके साथ, मूल रूप से एक विशेषता वस्तु के संदर्भ को निम्न रूप में दर्शाया गया है:

struct TraitObjectRef {
    data_ptr: *const (),
    vptr: *const (),
}

(यह C ++ से अलग है, जहां अमूर्त वर्गों के लिए vptr को ऑब्जेक्ट के भीतर संग्रहीत किया जाता है। दोनों दृष्टिकोणों के फायदे और नुकसान हैं।)


कस्टम डीएसटी

वास्तव में यह संभव है कि एक ऐसा ढांचा तैयार किया जाए जिसमें एक आखिरी क्षेत्र एक डीएसटी हो। हालांकि यह दुर्लभ है, हालांकि। एक प्रमुख उदाहरण है std::path::Path

कस्टम DST का एक संदर्भ या सूचक भी एक वसा सूचक है। अतिरिक्त डेटा संरचना के अंदर डीएसटी के प्रकार पर निर्भर करता है।


अपवाद: बाहरी प्रकार

में आरएफसी 1861 , extern typeसुविधा शुरू की गई थी। बाहरी प्रकार भी डीएसटी हैं, लेकिन उनके लिए संकेत वसा बिंदु नहीं हैं । या अधिक बिल्कुल, जैसा कि RFC डालता है:

जंग में, डीएसटी को इंगित किए गए ऑब्जेक्ट के बारे में डीएसटी के लिए संकेत मेटाडेटा ले जाते हैं। स्ट्रिंग्स और स्लाइस के लिए यह बफर की लंबाई है, विशेषता वस्तुओं के लिए यह ऑब्जेक्ट की वाइबेट है। बाहरी प्रकारों के लिए मेटाडेटा बस है ()। इसका मतलब यह है कि बाहरी प्रकार के लिए एक सूचक का आकार एक ही है usize(यानी यह "वसा सूचक" नहीं है)।

लेकिन अगर आप सी इंटरफेस के साथ बातचीत नहीं कर रहे हैं, तो आप शायद कभी भी इन बाहरी प्रकारों से नहीं निपटेंगे।




ऊपर, हमने अपरिवर्तनीय संदर्भों के लिए आकार देखे हैं। फैट पॉइंटर्स परस्पर संदर्भों, अपरिवर्तनीय रॉ पॉइंटर्स और म्यूटेबल रॉ पॉइंटर्स के लिए समान कार्य करते हैं:

size_of::<&[u32]>()       = 16
size_of::<&mut [u32]>()   = 16
size_of::<*const [u32]>() = 16
size_of::<*mut [u32]>()   = 16
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.