स्मार्ट संकेत: वस्तु का मालिक कौन है? [बन्द है]


114

C ++ स्मृति स्वामित्व के बारे में है - उर्फ स्वामित्व शब्दार्थ

यह उस स्मृति को जारी करने के लिए गतिशील रूप से आवंटित स्मृति के एक हिस्से के मालिक की जिम्मेदारी है। तो सवाल वास्तव में स्मृति का मालिक कौन हो जाता है।

C ++ ओनरशिप में प्रलेखित होता है जिस प्रकार से एक रॉ पॉइंटर को इस तरह से एक अच्छे (IMO) C लिपि में लपेटा जाता है। यह बहुत ही दुर्लभ ( दुर्लभ , कभी नहीं ) होता है। यह नहीं बताएं कि स्मृति का मालिक कौन है और इस तरह प्रलेखन के सावधानीपूर्वक पढ़ने के बिना आप यह नहीं बता सकते कि स्वामित्व के लिए कौन जिम्मेदार है)।

इसके विपरीत, एक वर्ग में संग्रहीत कच्चे पॉइंटर्स को देखना दुर्लभ है, प्रत्येक कच्चे पॉइंटर को अपने स्वयं के स्मार्ट पॉइंटर रैपर में संग्रहीत किया जाता है। ( एनबी: यदि आपके पास कोई वस्तु नहीं है, तो आपको इसे संग्रहीत नहीं करना चाहिए क्योंकि आप नहीं जान सकते कि यह कब दायरे से बाहर हो जाएगा और नष्ट हो जाएगा।)

तो सवाल:

  • किस प्रकार के स्वामित्व वाले शब्दार्थ लोगों के पार आ गए हैं?
  • उन शब्दार्थों को लागू करने के लिए किस मानक वर्ग का उपयोग किया जाता है?
  • आप उन्हें किन स्थितियों में उपयोगी पाते हैं?

प्रति उत्तर में 1 प्रकार के शब्दार्थ स्वामित्व रखते हैं ताकि उन्हें व्यक्तिगत रूप से वोट दिया जा सके।

सारांश:

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

std::auto_ptr<T>:

एकल व्यक्ति वस्तु का मालिक है। स्वामित्व के हस्तांतरण की अनुमति है।

उपयोग: यह आपको उन इंटरफेस को परिभाषित करने की अनुमति देता है जो स्वामित्व के स्पष्ट हस्तांतरण को दर्शाते हैं।

boost::scoped_ptr<T>

एकल व्यक्ति वस्तु का मालिक है। स्वामित्व के हस्तांतरण की अनुमति नहीं है।

उपयोग: स्पष्ट स्वामित्व दिखाने के लिए उपयोग किया जाता है। ऑब्जेक्ट विध्वंसक या स्पष्ट रूप से रीसेट होने पर नष्ट हो जाएगा।

boost::shared_ptr<T>( std::tr1::shared_ptr<T>)

एकाधिक स्वामित्व। यह एक साधारण रेफरेंस काउंटेड पॉइंटर है। जब संदर्भ संख्या शून्य तक पहुंच जाती है, तो वस्तु नष्ट हो जाती है।

उपयोग: जब कोई वस्तु जीवन भर के साथ कई owers हो सकती है जो संकलन समय पर निर्धारित नहीं की जा सकती है।

boost::weak_ptr<T>:

shared_ptr<T>उन स्थितियों में उपयोग किया जाता है जहां संकेत का एक चक्र हो सकता है।

उपयोग: चक्रों को बनाए रखने से वस्तुओं को रोकने के लिए उपयोग किया जाता है जब केवल चक्र एक साझा प्रतिधारण बनाए रखता है।


14
?? सवाल क्या था?
पचेरियर

9
मैं केवल यह बताना चाहता था कि चूंकि यह प्रश्न पोस्ट किया गया था इसलिए auto_ptr को (अब स्टैंडराइज्ड) unique_ptr के पक्ष में पदावनत किया गया है
जुआन कैम्पा

In C++ ownership is documented by the type a RAW pointer is wrapped inside thus in a good (IMO) क्या इसे रीफ़्रेश किया जा सकता है? मैं इसे बिल्कुल नहीं समझता।
लोलोलोल ओल

@lololololol आपने आधे में वाक्य काट दिया। In C++ ownership is documented by the type a RAW pointer is wrapped inside thus in a good C++ program it is very rare to see RAW pointers passed around। रॉ पॉइंटर्स के पास स्वामित्व शब्दार्थ नहीं है। यदि आप उस स्वामी को नहीं जानते हैं जो आप नहीं जानते हैं कि ऑब्जेक्ट को हटाने के लिए कौन जिम्मेदार है। कई मानक वर्ग हैं जो पॉइंटर्स को लपेटने के लिए उपयोग किए जाते हैं (std :: साझा_ptr, std :: unique_ptr आदि) जो स्वामित्व को परिभाषित करते हैं और इस प्रकार परिभाषित करें कि पॉइंटर को हटाने के लिए कौन जिम्मेदार है।
मार्टिन यॉर्क

1
C ++ 11 + में Auto_ptr का उपयोग न करें! इसके बजाय unique_ptr का उपयोग करें!
वैल का कहना है कि मोनिका

जवाबों:


20

मेरे लिए, ये 3 प्रकार मेरी जरूरतों को पूरा करते हैं:

shared_ptr - जब काउंटर शून्य पर पहुंचता है तो संदर्भ-गणना की जाती है

weak_ptr- ऊपर के रूप में ही है, लेकिन यह एक के लिए एक 'गुलाम' है shared_ptr, निपटा नहीं सकते

auto_ptr- जब सृजन और डील-डौल एक ही फ़ंक्शन के अंदर होता है, या जब ऑब्जेक्ट को केवल एक-स्वामी माना जाता है। जब आप एक पॉइंटर को दूसरे को असाइन करते हैं, तो दूसरा 'ऑब्जेक्ट' को पहले से चुरा लेता है।

इनके लिए मेरा अपना कार्यान्वयन है, लेकिन वे इसमें भी उपलब्ध हैं Boost

मैं अभी भी संदर्भ द्वारा वस्तुओं को पारित करता हूं ( constजब भी संभव हो), इस मामले में कहा जाता है कि विधि को कॉल के समय के दौरान ही जीवित होना चाहिए।

एक अन्य प्रकार का पॉइंटर है जिसका उपयोग मैं करता हूं कि मैं hub_ptr कहता हूं । यह तब होता है जब आपके पास एक ऐसी वस्तु होती है जो उसमें निहित वस्तुओं (आमतौर पर एक आभासी आधार वर्ग) से सुलभ होनी चाहिए। यह weak_ptrउन्हें पास करके हल किया जा सकता है , लेकिन यह अपने आप में नहीं है shared_ptr। जैसा कि यह जानता है कि ये वस्तुएं उससे अधिक समय तक जीवित नहीं रहेंगी, यह उनके लिए एक हब_पार्ट पास करता है (यह एक नियमित संकेतक के लिए सिर्फ एक टेम्पलेट आवरण है)।


2
अपने स्वयं के पॉइंटर क्लास (हब_प्ट्र) बनाने के बजाय, आप इन वस्तुओं को सिर्फ * पास क्यों नहीं करते हैं और इसे एक संदर्भ के रूप में संग्रहीत करते हैं? चूँकि आप यह भी स्वीकार करते हैं कि ऑब्जेक्ट्स को उसी वर्ग के रूप में नष्ट किया जाएगा, इसलिए मैं इतने बड़े हुप्स के माध्यम से कूदने की बात को नहीं समझता।
मिशेल

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

1
यह भी ध्यान दें कि आपके पास हब बिल्ड में नग्न सूचक के लिए hub_ptr टाइप करने के लिए #ifdefs हो सकते हैं, इसलिए ओवरहेड केवल डीबग बिल्ड में मौजूद होगा।
फैबियो सेकोनेलो

3
ध्यान दें कि बूस्ट प्रलेखन scoped_ptr के आपके विवरण का खंडन करता है। यह बताता है कि यह है noncopyableऔर यह स्वामित्व हस्तांतरित नहीं किया जा सकता है।
एलेक थॉमस

3
@ एलेक थॉमस, आप सही कह रहे हैं। मैं auto_ptr के बारे में सोच रहा था और scoped_ptr लिखा था। सही किया।
फाबियो सेकोनेलो

23

सरल सी ++ मॉडल

अधिकांश मॉड्यूल में मैंने देखा, डिफ़ॉल्ट रूप से, यह मान लिया गया था कि प्राप्त करने वाले संकेत स्वामित्व प्राप्त नहीं कर रहे थे। वास्तव में, सूचक के स्वामित्व को छोड़ने वाले कार्य / तरीके दोनों ही बहुत दुर्लभ थे और स्पष्ट रूप से उस तथ्य को उनके प्रलेखन में व्यक्त किया गया था।

यह मॉडल मानता है कि उपयोगकर्ता केवल वही है जो वह स्पष्ट रूप से आवंटित करता है । बाकी सब कुछ स्वचालित रूप से (गुंजाइश से बाहर निकलने पर, या RAII के माध्यम से) निपटाया जाता है। यह एक सी-लाइक मॉडल है, जिसे इस तथ्य द्वारा विस्तारित किया जाता है कि ज्यादातर पॉइंटर्स ऑब्जेक्ट्स के स्वामित्व में होते हैं जो उन्हें स्वचालित रूप से या जब जरूरत होगी (कहा वस्तुओं के विनाश, ज्यादातर) से निपटते हैं, और यह कि वस्तुओं की जीवन अवधि पूर्वानुमेय है (RAII आपका मित्र है,) फिर)।

इस मॉडल में, कच्चे पॉइंटर्स स्वतंत्र रूप से घूम रहे हैं और ज्यादातर खतरनाक नहीं हैं (लेकिन यदि डेवलपर पर्याप्त स्मार्ट है, तो वह जब भी संभव हो, संदर्भों का उपयोग करेगा)।

  • कच्चे संकेत
  • std :: auto_ptr
  • बढ़ावा :: scoped_ptr

स्मार्ट पॉइंटेड C ++ मॉडल

स्मार्ट पॉइंटर्स से भरे कोड में, उपयोगकर्ता वस्तुओं के जीवनकाल को अनदेखा करने की उम्मीद कर सकता है। मालिक कभी भी उपयोगकर्ता कोड नहीं होता है: यह खुद स्मार्ट पॉइंटर है (RAII, फिर से)। समस्या यह है कि संदर्भ में गिने जाने वाले स्मार्ट पॉइंटर्स के साथ मिश्रित परिपत्र संदर्भ घातक हो सकते हैं , इसलिए आपको दोनों साझा पॉइंटर्स और कमजोर पॉइंटर्स दोनों से निपटना होगा। तो आपके पास अभी भी विचार करने के लिए स्वामित्व है (कमजोर सूचक अच्छी तरह से कुछ भी नहीं इंगित कर सकता है, भले ही कच्चे सूचक पर इसका लाभ यह है कि यह आपको ऐसा बता सकता है)।

  • बढ़ावा :: shared_ptr
  • बढ़ावा :: weak_ptr

निष्कर्ष

कोई मॉडल मैं का वर्णन है, कोई फर्क जब तक अपवाद, प्राप्त एक सूचक है नहीं इसके स्वामित्व प्राप्त करने और यह अभी भी पता है, जो जो मालिक है बहुत महत्वपूर्ण है । यहां तक ​​कि संदर्भों और / या स्मार्ट पॉइंटर्स का उपयोग करके सी ++ कोड के लिए भारी।


10

साझा स्वामित्व नहीं है। यदि आप करते हैं, तो सुनिश्चित करें कि यह केवल उस कोड के साथ है जिसे आप नियंत्रित नहीं करते हैं।

यह 100% समस्याओं को हल करता है, क्योंकि यह आपको यह समझने के लिए मजबूर करता है कि सब कुछ कैसे इंटरैक्ट करता है।


2
  • साझा स्वामित्व
  • बढ़ावा :: shared_ptr

जब एक संसाधन कई वस्तुओं के बीच साझा किया जाता है। बूस्ट शेयर्ड_पिट्र रेफरेंस काउंटिंग का उपयोग करता है यह सुनिश्चित करने के लिए कि हर कोई फ़ाइनसीड होने पर संसाधन डी-आबंटित हो।


2

std::tr1::shared_ptr<Blah> अक्सर आपका सबसे अच्छा दांव होता है।


2
share_ptr सबसे आम है। लेकिन कई और भी हैं। प्रत्येक का अपना उपयोग पैटर्न और मुकदमा करने के लिए अच्छे और बुरे स्थान हैं। थोड़ा और विवरण अच्छा होगा।
मार्टिन यॉर्क

यदि आप एक पुराने संकलक के साथ फंस गए हैं, तो बढ़ावा दें :: shared_ptr <blah> क्या std :: tr1 :: साझा_ptr <blah> पर आधारित है। यह एक सरल पर्याप्त वर्ग है जिसे आप संभवतः बूस्ट से चीर सकते हैं और इसका उपयोग कर सकते हैं, भले ही आपका कंपाइलर बूस्ट के नवीनतम संस्करण द्वारा समर्थित न हो।
ब्रानन १

2

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

विंडोज पर, COM पॉइंटर्स (IUn परिचित, IDispatch और मित्र) हैं, और उन्हें संभालने के लिए विभिन्न स्मार्ट पॉइंटर्स (जैसे ATL के CComPtr और _com_ptr वर्ग पर आधारित विज़ुअल स्टूडियो में "इम्पोर्ट" स्टेटमेंट द्वारा ऑटो-जेनरेट किए गए स्मार्ट पॉइंट्स) )।


1
  • एक मालिक
  • बढ़ावा :: scoped_ptr

जब आपको स्मृति को गतिशील रूप से आवंटित करने की आवश्यकता होती है, लेकिन यह सुनिश्चित करना चाहते हैं कि यह ब्लॉक के प्रत्येक निकास बिंदु पर निपटा जाए।

मुझे यह उपयोगी लगता है क्योंकि इसे आसानी से बचाया जा सकता है, और कभी भी रिसाव के बारे में चिंता किए बिना जारी किया जाता है


1

मुझे नहीं लगता कि मैं कभी अपने डिजाइन में साझा स्वामित्व रखने की स्थिति में था। वास्तव में, मेरे सिर के ऊपर से एकमात्र वैध मामला है जिसके बारे में मैं सोच सकता हूं कि फ्लाईवेट पैटर्न है।


1

yasper :: ptr एक हल्का, बढ़ावा देने वाला :: वैकल्पिक की तरह साझा किया गया। यह मेरे (अभी के लिए) छोटे प्रोजेक्ट में अच्छा काम करता है।

Http://yasper.sourceforge.net/ पर वेब पेज में इसका वर्णन इस प्रकार है:

दूसरा C ++ स्मार्ट पॉइंटर क्यों लिखें? C ++ के लिए पहले से ही कई उच्च गुणवत्ता वाले स्मार्ट पॉइंटर कार्यान्वयन मौजूद हैं, जिनमें से सबसे प्रमुख रूप से बूस्टर पॉइंटर पेंथियन और लोकी का स्मार्टहार्ट है। स्मार्ट पॉइंटर कार्यान्वयन की एक अच्छी तुलना के लिए और जब उनका उपयोग उचित हो तो हर्ब सटर की द न्यू C ++: स्मार्ट (एर) पॉइंटर्स पढ़ें। अन्य पुस्तकालयों की विस्तृत विशेषताओं के विपरीत, यास्पर एक संकरी रूप से केंद्रित संदर्भ गणना सूचक है। यह बूस्ट के शेयर्ड_एप्ट्र और लोकी की रिफांकेड / एस्कॉनवर्सन नीतियों के साथ निकटता से मेल खाता है। यास्पर सी ++ प्रोग्रामर्स को बूस्ट की बड़ी निर्भरता को पेश किए बिना या लोकी की जटिल पॉलिसी टेम्प्लेट के बारे में जानने के बिना मेमोरी प्रबंधन के बारे में भूल जाने की अनुमति देता है। दर्शन

* small (contained in single header)
* simple (nothing fancy in the code, easy to understand)
* maximum compatibility (drop in replacement for dumb pointers)

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


1

एकल-हस्तांतरणीय-स्वामी का एक और अक्सर उपयोग किया जाने वाला रूप है, और यह बेहतर है auto_ptrक्योंकि यह auto_ptrअसाइनमेंट शब्दार्थ के भ्रष्टाचार के कारण होने वाली समस्याओं से बचा जाता है ।

मैं इसके अलावा किसी और की बात नहीं करता swap। एक उपयुक्त swapफ़ंक्शन के साथ किसी भी प्रकार की कल्पना कुछ सामग्री के लिए एक स्मार्ट संदर्भ के रूप में की जा सकती है, जो कि उस समय तक होती है जब तक कि स्वामित्व उसी प्रकार के दूसरे उदाहरण में स्थानांतरित नहीं होता है, उन्हें स्वैप करके। प्रत्येक उदाहरण अपनी पहचान बनाए रखता है लेकिन नई सामग्री के लिए बाध्य होता है। यह एक सुरक्षित रूप से विद्रोही संदर्भ की तरह है।

(यह एक स्मार्ट पॉइंटर के बजाय एक स्मार्ट संदर्भ है क्योंकि आपको सामग्री पर प्राप्त करने के लिए इसे स्पष्ट रूप से नहीं करना है।)

इसका मतलब यह है कि auto_ptr कम आवश्यक हो जाता है - यह केवल अंतराल को भरने के लिए आवश्यक है जहां प्रकारों का एक अच्छा swapकार्य नहीं होता है । लेकिन सभी एसटीडी कंटेनर करते हैं।


शायद यह कम आवश्यक हो जाता है (मैं कहूँगा कि scoped_ptr इसे इससे कम आवश्यक बनाता है), लेकिन यह दूर नहीं जा रहा है। यदि आप इसे हटाते हैं, या आप बस भूल जाते हैं, तो एक स्वैप फ़ंक्शन होने से आपको बिल्कुल भी मदद नहीं मिलती है, जब आप ढेर पर कुछ आवंटित करते हैं और कोई फेंकता है।
मिशेल

मैंने पिछले पैराग्राफ में यही कहा था।
डैनियल ईयरविकर

0
  • वन ओनर: कॉपी पर आका डिलीट
  • std :: auto_ptr

जब ऑब्जेक्ट का निर्माता स्पष्ट रूप से किसी और को स्वामित्व सौंपना चाहता है। यह भी एक तरीका है जिस कोड में मैं आपको यह दे रहा हूं और मैं अब इसे ट्रैक नहीं कर रहा हूं इसलिए सुनिश्चित करें कि जब आप समाप्त कर लें तो इसे हटा दें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.