tutorial - the c++ programming language




क्या स्मार्ट पॉइंटर्स का हमेशा उपयोग करना अच्छा अभ्यास है? (7)

आम तौर पर, नहीं, आप हमेशा स्मार्ट पॉइंटर्स का उपयोग नहीं कर सकते हैं। उदाहरण के लिए, जब आप अन्य ढांचे का उपयोग करते हैं जो स्मार्ट पॉइंटर (क्यूटी की तरह) का उपयोग नहीं करते हैं, तो आपको कच्चे पॉइंटर्स का भी उपयोग करना होगा।

मुझे कच्चे पॉइंटर्स की तुलना में स्मार्ट पॉइंटर्स बहुत अधिक आरामदायक लगता है। तो हमेशा स्मार्ट पॉइंटर्स का उपयोग करना एक अच्छा विचार है? (कृपया ध्यान दें कि मैं जावा पृष्ठभूमि से हूं और इसलिए स्पष्ट स्मृति प्रबंधन के विचार को बहुत पसंद नहीं है। इसलिए स्मार्ट पॉइंटर्स के साथ कुछ गंभीर प्रदर्शन समस्याएं होने तक, मैं उनके साथ रहना चाहूंगा।)

नोट: हालांकि मैं जावा पृष्ठभूमि से आया हूं, मैं स्मार्ट पॉइंटर्स और आरएआईआई की अवधारणाओं के कार्यान्वयन को अच्छी तरह से समझता हूं। तो उत्तर देने पर आप इस ज्ञान को मेरे पक्ष से प्राप्त कर सकते हैं। मैं लगभग हर जगह स्थिर आवंटन का उपयोग करता हूं और आवश्यक होने पर केवल पॉइंटर्स का उपयोग करता हूं। मेरा सवाल केवल है: क्या मैं हमेशा कच्चे पॉइंटर्स के स्थान पर स्मार्ट पॉइंटर्स का उपयोग कर सकता हूं ???


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

यह दृष्टिकोण (" RAII ") आपको ज्यादातर समय पॉइंटर्स के बारे में चिंता करने से बचाता है।

जब आपको पॉइंटर्स का उपयोग करना होता है तो यह स्थिति पर निर्भर करता है और आपको वास्तव में पॉइंटर्स की आवश्यकता क्यों होती है, लेकिन आमतौर पर स्मार्ट पॉइंटर्स का उपयोग किया जा सकता है। यह हमेशा (बोल्ड में) सबसे अच्छा विकल्प नहीं हो सकता है, लेकिन यह विशिष्ट स्थिति पर निर्भर करता है।


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


यदि आप संसाधन को प्रबंधित कर रहे हैं, तो आपको हमेशा आरएआईआई तकनीकों का उपयोग करना चाहिए, स्मृति के मामले में कुछ रूपों या किसी स्मार्ट पॉइंटर का उपयोग करने का मतलब है (नोट: स्मार्ट, shared_ptr नहीं किया गया है, स्मार्ट पॉइंटर चुनें जो आपके विशिष्ट उपयोग के लिए सबसे उपयुक्त है मामला)। अपवादों की उपस्थिति में लीक से बचने का यही एकमात्र तरीका है।

ऐसे मामले भी हैं जहां कच्चे पॉइंटर्स आवश्यक हैं, जब संसाधन प्रबंधन को सूचक के माध्यम से संभाला नहीं जाता है। विशेष रूप से वे एक resetable संदर्भ होने का एकमात्र तरीका हैं। उस वस्तु में संदर्भ रखने के बारे में सोचें जिसका जीवनकाल स्पष्ट रूप से संभाला नहीं जा सकता (सदस्य विशेषता, ढेर में वस्तु)। लेकिन यह एक बहुत ही विशिष्ट मामला है जिसे मैंने केवल वास्तविक कोड में देखा है। ज्यादातर मामलों में, किसी shared_ptr का उपयोग करना किसी ऑब्जेक्ट को साझा करने का एक बेहतर तरीका है।


स्मार्ट पॉइंटर्स का उपयोग करने का एक अच्छा समय, डीएलएल की इंटरफ़ेस सीमा पर है। आप नहीं जानते कि अन्य निष्पादक एक ही संकलक / पुस्तकालयों के साथ बनाए जाएंगे या नहीं। आपके सिस्टम का डीएलएल कॉलिंग सम्मेलन यह निर्दिष्ट नहीं करेगा कि मानक पॉइंटर्स में कौन से मानक या टीआर 1 वर्ग दिखते हैं।

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

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

एक और मामूली मामला: मैं देखना चाहता हूं कि फ़ंक्शंस पॉइंटर या संदर्भ द्वारा पैरामीटर लेते हैं, और वादा करता है कि आप एक पॉइंटर या संदर्भ को बनाए रखने का वादा नहीं करते हैं , बजाय shared_ptr लेते हैं और आपको यह सोचते हुए छोड़ देते हैं कि वे वापस लौटने के बाद संदर्भ बनाए रखते हैं या नहीं यदि आप फिर से संदर्भ को संशोधित करते हैं तो आप कुछ तोड़ देंगे, आदि। संदर्भों को बनाए रखना कुछ ऐसा नहीं है जिसे अक्सर स्पष्ट रूप से दस्तावेज नहीं किया जाता है, यह बिना कहने के चला जाता है। शायद यह नहीं होना चाहिए, लेकिन यह करता है। स्मार्ट पॉइंटर्स स्वामित्व के बारे में कुछ बताते हैं, और झूठा अर्थ यह है कि भ्रमित हो सकता है। तो यदि आपका फ़ंक्शन एक shared_ptr लेता है, तो यह सुनिश्चित करना सुनिश्चित करें कि क्या यह संदर्भ बनाए रख सकता है या नहीं।


स्मार्ट पॉइंटर्स स्पष्ट मेमोरी प्रबंधन करते हैं, और यदि आप समझ नहीं पाते कि वे इसे कैसे कर रहे हैं, तो सी ++ के साथ प्रोग्रामिंग करते समय आप परेशानी की दुनिया में हैं। और याद रखें कि स्मृति एकमात्र संसाधन नहीं है जिसे वे प्रबंधित करते हैं।

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

string * s1 = new string( "foo" );      // bad
string s2( "bar" );    // good

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


हां लेकिन मैं स्मार्ट पॉइंटर या किसी पॉइंटर्स के उपयोग के बिना कई परियोजनाएं चला गया हूं। डेक, सूची, मानचित्र इत्यादि जैसे कंटेनर का उपयोग करने के लिए यह अच्छा अभ्यास है वैकल्पिक रूप से जब संभव हो तो मैं संदर्भों का उपयोग करता हूं। एक सूचक में गुजरने के बजाय मैं एक संदर्भ या कॉन्स्ट संदर्भ पास करता हूं और संदर्भ को हटाने / मुक्त करने के लिए लगभग हमेशा अनौपचारिक होता हूं, इसलिए मुझे वहां कोई समस्या नहीं होती है (आमतौर पर मैं उन्हें लिखकर स्टैक पर बना देता हूं { Class class; func(class, ref2, ref3); }





c++