2011-04-15 14 views
51

मैं समझता हूं कि weak_ptr और shared_ptr का उपयोग कैसे करें। मैं समझता हूं कि shared_ptr इसकी वस्तु में संदर्भों की संख्या की गणना करके काम करता है। weak_ptr कैसे काम करता है? मैंने बूस्ट सोर्स कोड के माध्यम से पढ़ने की कोशिश की, और मैं उन सभी चीजों को समझने के लिए बूस्ट के साथ पर्याप्त परिचित नहीं हूं।weak_ptr कैसे काम करता है?

धन्यवाद।

+6

यह भी देखें: [साझा पॉइंटर्स कैसे काम करते हैं?] (Http://stackoverflow.com/questions/2802953/how-do-shared-pointers-work) –

+0

यह भी देखें [shared_ptr कार्यान्वयन नोट] (http: // en.cppreference.com/w/cpp/memory/shared_ptr#Implementation_notes) – ks1322

उत्तर

85

shared_ptr संदर्भ गणना को संग्रहीत करने के लिए अतिरिक्त "काउंटर" ऑब्जेक्ट (उर्फ। "साझा गणना" या "नियंत्रण ब्लॉक") का उपयोग करता है। (BTW: कि "काउंटर" वस्तु भी Deleter संग्रहीत करता है।)

हर shared_ptr और weak_ptr वास्तविक pointee के लिए सूचक है, और "काउंटर" वस्तु के लिए एक दूसरी सूचक होता है।

weak_ptr, "काउंटर" वस्तु भंडार दो अलग-अलग काउंटरों को लागू करने के लिए:

  • "उपयोग गिनती" shared_ptr उदाहरणों वस्तु की ओर इशारा करते की संख्या है।
  • "कमजोर गिनती" weak_ptr एक वस्तु की ओर इशारा करते उदाहरणों, प्लस की संख्या अगर "उपयोग गिनती" अभी भी है> 0.

जब "उपयोग गिनती" शून्य पर पहुंच pointee हटा दी जाती है ।

"काउंटर" सहायक वस्तु हटा दी जाती है जब "कमजोर गिनती" शून्य तक पहुंच जाती है (जिसका अर्थ है कि "उपयोग गणना" शून्य भी होनी चाहिए, ऊपर देखें)।

जब आप से shared_ptr प्राप्त करने का प्रयास करते हैं, तो लाइब्रेरी परमाणु रूप से "उपयोग गणना" की जांच करता है, और यदि यह> 0 इसे बढ़ाता है। यदि यह सफल होता है तो आपको अपना shared_ptr मिलता है। यदि "उपयोग गणना" पहले ही शून्य थी तो आपको इसके बजाय shared_ptr उदाहरण खाली मिला।


संपादित: अब, क्यों वे एक कमजोर गिनती के बजाय जोड़ने बस "काउंटर" वस्तु को रिहा दोनों की गिनती शून्य करने के लिए छोड़ जब करते हैं? अच्छा प्रश्न।

विकल्प "काउंटर" ऑब्जेक्ट को हटाना होगा जब "उपयोग गणना" और "कमजोर गिनती" दोनों शून्य हो जाएंगे। यहां पहला कारण है: प्रत्येक प्लेटफ़ॉर्म पर दो (पॉइंटर आकार) काउंटर परमाणु रूप से जांचना संभव नहीं है, और यहां तक ​​कि यह कहां है, यह केवल एक काउंटर की जांच करने से अधिक जटिल है।

एक और कारण यह है कि डिलीटर निष्पादित होने तक वैध रहना चाहिए। चूंकि डिलीटर "काउंटर" ऑब्जेक्ट में संग्रहीत होता है, इसका मतलब है कि "काउंटर" ऑब्जेक्ट वैध होना चाहिए। गौर करें कि क्या हो सकता है यदि कोई shared_ptr और एक weak_ptr किसी ऑब्जेक्ट में हो, और वे समवर्ती धागे में एक ही समय में रीसेट हो जाएं। मान लें कि shared_ptr पहले आता है। यह शून्य पर "उपयोग गणना" को कम करता है, और हटाए जाने वाले को निष्पादित करना शुरू करता है। अब weak_ptr शून्य पर "कमजोर गिनती" को कम करता है, और "उपयोग गणना" शून्य भी शून्य पाता है। तो यह "काउंटर" ऑब्जेक्ट को हटा देता है, और इसके साथ हटाना। जबकि डिलीटर अभी भी चल रहा है।

बेशक वहाँ अलग अलग तरीकों से आश्वस्त करने के लिए है कि "काउंटर" वस्तु जीवित रहता होगा, लेकिन मुझे लगता है कि एक के बाद "कमजोर गिनती" में वृद्धि एक बहुत ही सुंदर और सहज ज्ञान युक्त समाधान है। "काउंटर" ऑब्जेक्ट के लिए "कमजोर गिनती" संदर्भ गणना बन जाती है।और चूंकि shared_ptr काउंटर ऑब्जेक्ट को भी संदर्भित करता है, इसलिए उन्हें भी "कमजोर गिनती" बढ़ाना पड़ता है।

शायद एक और अधिक सहज समाधान प्रत्येक shared_ptr के लिए "कमजोर गिनती" को बढ़ाने के लिए होगा, क्योंकि प्रत्येक एकल shared_ptr होल्ड "ऑब्जेक्ट" ऑब्जेक्ट का संदर्भ है।

सभी shared_ptr उदाहरणों के लिए एक जोड़ना सिर्फ एक अनुकूलन है (shared_ptr उदाहरणों को प्रतिलिपि/असाइन करते समय एक परमाणु वृद्धि/कमी बचाता है)।

+0

वे जांच नहीं करते हैं कि कमजोर गिनती और उपयोग गणना शून्य है, और फिर काउंटर ऑब्जेक्ट को हटा दें। लेकिन अगर वे गिनती का उपयोग गैर-शून्य है, तो इसके बाद वे कमजोर गिनती को बढ़ाते हैं, और फिर केवल कमजोर गिनती की जांच करें। ऐसा क्यों है? –

+0

चूंकि यह केवल एक टिप्पणी के साथ व्याख्या करने के लिए थोड़ा मुश्किल है, इसलिए मैंने अपना जवाब अपडेट किया। –

+0

संभवतः वे केवल 1 को जोड़ते हैं और प्रत्येक shared_ptr के लिए 1 नहीं है कि तब उन्हें केवल काउंटर ऑब्जेक्ट को स्पर्श करने की आवश्यकता होती है जब उन्हें हटाने के लिए किसी भी तरह से इसे स्पर्श करने की आवश्यकता होती है, और हर बार जब वे उपयोग काउंटर को कम नहीं करते हैं? –

-5

असल में, एक "कमजोर_पीटीआर" एक साधारण "टी *" सूचक है जो आपको बाद में कोड में एक मजबूत संदर्भ, यानी "shared_ptr" प्राप्त करने देता है।

बस एक साधारण टी * की तरह, कमजोर_प्टर कोई संदर्भ-गणना नहीं करता है। आंतरिक रूप से, मनमानी प्रकार टी, एसटीएल (या इस तरह के तर्क को लागू करने वाली कोई अन्य लाइब्रेरी) पर संदर्भ-गणना का समर्थन करने के लिए एक रैपर ऑब्जेक्ट बनाता है जिसे हम "एंकर" कहते हैं। "एंकर" संदर्भ गणना को लागू करने के लिए पूरी तरह से मौजूद है और "जब गिनती शून्य है, कॉल हटाएं" जिस व्यवहार की हमें आवश्यकता है।

एक मजबूत संदर्भ में, shared_ptr अपनी प्रतिलिपि, ऑपरेटर =, कन्स्ट्रक्टर, विनाशक, और अन्य प्रासंगिक API को "एंकर" संदर्भ गणना को अद्यतन करने के लिए लागू करता है। इस प्रकार एक shared_ptr यह सुनिश्चित करता है कि आपका "टी" वास्तव में तब तक रहता है जब तक कोई इसका उपयोग कर रहा हो। "Weak_ptr" में, वही एपीआई बस वास्तविक एंकर पीआरटी की प्रतिलिपि बनाते हैं। वे संदर्भ गणना अद्यतन नहीं करते हैं।

यही कारण है कि "weak_ptr" के सबसे महत्वपूर्ण एपीआई "समाप्त हो गए" और खराब नाम वाले "लॉक" हैं। "कालबाह्य" आपको बताता है कि अंतर्निहित वस्तु अभी भी आसपास है यानी "क्या यह पहले से ही हटा दी गई है क्योंकि सभी मजबूत संदर्भ दायरे से बाहर हो गए हैं?"। "लॉक" होगा (अगर यह कर सकता है) weak_ptr को एक मजबूत संदर्भ shared_ptr में परिवर्तित करें, संदर्भ-गणना को पुनर्स्थापित करें।

बीटीडब्ल्यू, "लॉक" उस एपीआई के लिए एक भयानक नाम है। आप (सिर्फ) एक म्यूटेक्स का आह्वान नहीं कर रहे हैं, आप एक कमजोर व्यक्ति से एक मजबूत संदर्भ बना रहे हैं, जिसमें "एंकर" अभिनय है। दोनों टेम्पलेट्स में सबसे बड़ी खामियां यह है कि उन्होंने ऑपरेटर-> को लागू नहीं किया है, इसलिए अपनी वस्तु के साथ कुछ भी करने के लिए आपको कच्चे "टी *" को पुनर्प्राप्त करना होगा। उन्होंने इसे "shared_ptr" जैसी चीजों का समर्थन करने के लिए किया, क्योंकि आदिम प्रकार ऑपरेटर का समर्थन नहीं करते हैं।

+4

आपने लिखा: * "weak_ptr" में, वही एपीआई बस वास्तविक एंकर पीआरटी की प्रतिलिपि बनाते हैं। वे संदर्भ संख्या अद्यतन नहीं करते हैं। * यह गलत है; वे * कमजोर * संदर्भ गिनती को अद्यतन करते हैं, जो एंकर के जीवनकाल को स्वयं प्रबंधित करता है। अन्यथा, आप एंकर की अपनी याददाश्त को कब मुक्त करना चाहते हैं? साथ ही, 'std :: shared_ptr' * करता है * ऑपरेटर->' लागू करें; मुझे नहीं पता कि आपको यह विचार कैसे मिला कि यह नहीं है। – Quuxplusone

+0

एसटीएल मानक टेम्पलेट लाइब्रेरी का संक्षिप्त नाम है, यानी कंटेनर, इटरेटर आदि। स्मार्ट पॉइंटर्स इसका हिस्सा नहीं हैं। – curiousguy

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