23

दूसरे शब्दों में, कार्यान्वयन कैसे गिनती का ट्रैक रखता है?एक संदर्भ-गणना स्मार्ट सूचक का संदर्भ गिनती कैसे काम करता है?

क्या कोई मानचित्र-जैसी वस्तु है जो सभी shared_ptr उदाहरणों के द्वारा सुलभ है, जिनकी कुंजी सूचक का पता है और मान संदर्भों की संख्या है? अगर मुझे shared_ptr लागू करना है, तो यह पहला विचार है जो मेरे दिमाग में आ रहा है।

क्या इन संदर्भ-गणना स्मार्ट पॉइंटर्स के मामले में स्मृति रिसाव की संभावना है? यदि हां, तो मैं उनसे कैसे बच सकता हूं?

उत्तर

58

मैं इस के लिए दो अलग-अलग गैर दखल दृष्टिकोण को देखा है:

  1. स्मार्ट सूचक स्मृति का एक छोटा सा ब्लॉक संदर्भ काउंटर को रोकने के लिए आवंटित करता है। स्मार्ट पॉइंटर की प्रत्येक प्रति को वास्तविक ऑब्जेक्ट पर पॉइंटर और संदर्भ गणना के लिए पॉइंटर प्राप्त होता है।
  2. एक वस्तु सूचक के अलावा, प्रत्येक स्मार्ट सूचक एक पिछले और अगले सूचक है, जिससे एक विशेष वस्तु को स्मार्ट संकेत के दोगुना से जुड़े सूची बनाने में शामिल है। संदर्भ संख्या सूची में निहित है। जब एक स्मार्ट पॉइंटर की प्रतिलिपि बनाई जाती है, तो यह सूची को सूची में जोड़ती है। विनाश पर, प्रत्येक स्मार्ट पॉइंटर सूची से खुद को हटा देता है। यदि यह में अंतिम बार है तो यह सूची संदर्भित ऑब्जेक्ट को भी मुक्त करती है।

यदि आप here पर जाते हैं और नीचे स्क्रॉल करते हैं, तो एक उत्कृष्ट आरेख है जो इन तरीकों को और अधिक स्पष्ट रूप से समझाता है।

+0

यह सबसे सही जवाब है। –

+2

लिंक-सूची दृष्टिकोण अतिरिक्त आवंटन से बचाता है, लेकिन वैश्विक म्यूटेक्स के बिना "थ्रेड-सुरक्षित" बनाना बहुत मुश्किल है। ("थ्रेड-सुरक्षित" जैसे "कच्चे सूचक के रूप में थ्रेड-सुरक्षित" के रूप में) – curiousguy

+2

यदि आप 'make_shared' का उपयोग करते हैं, तो यह आवंटित ऑब्जेक्ट और इंस्टेंस काउंटर को स्मृति के एक ब्लॉक में डालकर अतिरिक्त आवंटन से भी बचा सकता है। – Ferruccio

2

नहीं shared_ptr संदर्भ गणना के लिए केवल एक अतिरिक्त सूचक रखें।

जब आप shared_ptr ऑब्जेक्ट की प्रतिलिपि बनाते हैं तो यह संदर्भों की गिनती के साथ पॉइंटर की प्रतिलिपि बनाता है, इसे बढ़ाता है, और निहित ऑब्जेक्ट पर पॉइंटर कॉपी करता है।

2

संदर्भ-गणना स्मार्ट पॉइंटर्स के साथ मेमोरी रिसाव बनाना बहुत आसान है। बस उन ऑब्जेक्ट्स की ग्राफ-जैसी संरचना बनाएं जिनमें ग्राफ़ में एक चक्र है। चक्र में वस्तुओं को एक दूसरे को रिहा होने से रोक देगा। इसे स्वचालित रूप से हल नहीं किया जा सकता है - उदाहरण के लिए, जब आप एक डबल-लिंक सूची बनाते हैं तो आपको एक समय में एक से अधिक ऑब्जेक्ट को कभी भी हटाने का ख्याल रखना पड़ता है।

3

प्रत्येक स्मार्ट पॉइंटर ऑब्जेक्ट में एक साझा संदर्भ गणना होती है - प्रत्येक कच्चे सूचक के लिए एक।

आप this आलेख पर एक नज़र डाल सकते हैं। यह कार्यान्वयन इन्हें एक अलग वस्तु में संग्रहीत करता है जिसे प्रतिलिपि बनाई जाती है। आप boost's documentation पर भी एक नज़र डालें या स्मार्ट पॉइंटर्स पर Wikipedia article पर एक नज़र डालें।

+0

-1। सभी स्मार्ट पॉइंटर्स जो एक ही ऑब्जेक्ट को संदर्भित करते हैं * एक * संदर्भ संदर्भ साझा करना चाहिए। संदर्भ गणना धारण करने वाली ऑब्जेक्ट को पहले स्मार्ट पॉइंटर ऑब्जेक्ट द्वारा आवंटित किया जाता है, और * पॉइंटर्स * * (ऑब्जेक्ट स्वयं नहीं) कॉपी किए जाते हैं जब स्मार्ट पॉइंटर कॉपी किया जाता है। –

+0

j_random_hacker पर सहमत हैं। गिनती प्रत्येक कच्चे सूचक के लिए अद्वितीय है और सभी साझा_ptr द्वारा साझा की जाती है जो एक ही कच्चे सूचक का संदर्भ देती है। आम तौर पर इसे स्मृति के अलग-अलग हिस्से के रूप में आवंटित किया जाता है, इसलिए smart_ptr में दो आंतरिक ptrs, संदर्भ गणना के लिए एक और पॉइंटर के लिए दूसरा होता है। स्थिर चर के लिए –

+0

-1। जब तक आप एक सिंगलटन ऑब्जेक्ट में संदर्भ-गणना वाले स्मार्ट पॉइंटर को लागू नहीं कर रहे हैं, तो आप संदर्भ गणना को लागू करने के लिए statics का उपयोग नहीं कर सकते हैं। –

2

जहां तक ​​मुझे याद है, प्रभावी सी ++ के अध्याय में संदर्भित सूचक गणना की समस्या थी।

सिद्धांत रूप में, आपके पास "प्रकाश" पॉइंटर वर्ग होता है, जिसमें संदर्भ रखने वाले वर्ग में एक सूचक होता है जो संदर्भ/कमी संदर्भ को संदर्भित करता है और पॉइंटर ऑब्जेक्ट को नष्ट करता है। उस संदर्भ को संदर्भित करने के लिए ऑब्जेक्ट को कक्षा अंक गिनती है।

2

कई उत्तरों संदर्भ संख्या को संग्रहीत करने के तरीके को संबोधित करते हैं (यह सभी साझा_इंटर के लिए साझा स्मृति में संग्रहीत है जो एक ही देशी सूचक धारण करता है), लेकिन अधिकांश लीक की समस्या को दूर करते हैं।

संदर्भ गिनती पॉइंटर्स के साथ स्मृति को लीक करने का सबसे आसान तरीका चक्र बना रहा है। उदाहरण के तौर पर, एक दोगुनी लिंक्ड सूची जहां सभी पॉइंटर्स साझा_ptr कम से कम दो तत्वों के साथ हटाए जाने की गारंटी नहीं है। यहां तक ​​कि यदि बाहरी पॉइंटर्स मुक्त हो जाते हैं, तो आंतरिक पॉइंटर्स अभी भी गिना जाएगा, और संदर्भ संख्या 0 तक नहीं पहुंच जाएगी। कम से कम, सबसे भयानक कार्यान्वयन के साथ।

चक्र समस्या का सबसे आसान समाधान share_ptr (संदर्भ गिनती पॉइंटर्स) को कमजोर पॉइंटर्स के साथ मिलाकर ऑब्जेक्ट के स्वामित्व को साझा नहीं करता है।

साझा पॉइंटर्स संसाधन (सूचक) और अतिरिक्त संदर्भ_count दोनों जानकारी साझा करेंगे। जब आप कमजोर पॉइंटर्स का उपयोग करते हैं, तो संदर्भ गणना दोगुनी हो जाती है: एक साझा सूचक संदर्भ संख्या और एक कमजोर सूचक संदर्भ गणना होती है। जब भी साझा सूचक गणना 0 तक पहुंच जाती है तब संसाधन जारी किया जाता है, लेकिन संदर्भ कमांड जानकारी तब तक जीवित रहती है जब तक कि अंतिम कमजोर सूचक जारी नहीं किया जाता है।

दोगुनी लिंक्ड सूची में, बाहरी संदर्भ एक साझा_प्टर में आयोजित किया जाता है, जबकि आंतरिक लिंक केवल weak_ptr होते हैं। जब भी कोई बाहरी संदर्भ नहीं है (shared_ptr) सूची के तत्व जारी किए जाते हैं, कमजोर संदर्भों को हटाते हैं। अंत में सभी कमजोर संदर्भ हटा दिए गए हैं और प्रत्येक संसाधन के लिए अंतिम कमजोर पॉइंटर संदर्भ_count जानकारी को मुक्त करता है।

उपर्युक्त पाठ की तुलना में यह कम भ्रमित है ... मैं बाद में पुनः प्रयास करूंगा।

+2

आपने बाद में पुनः प्रयास नहीं किया। – xaxxon

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