2011-12-04 12 views
7

मैं किसी फ़ंक्शन के स्मार्ट-पॉइंटर संदर्भ द्वारा ऑब्जेक्ट पास करना चाहता हूं। फ़ंक्शन संदर्भित ऑब्जेक्ट का मान बदल सकता है, लेकिन संदर्भ को स्वयं नहीं बदल सकता है। इसे संभालने के दो स्पष्ट तरीके हैं।पैरामीटर के रूप में एक mutable ऑब्जेक्ट में shared_ptr को कैसे पास करें?

मूल्य_ द्वारा साझा_ptr को पास करने का पहला दृष्टिकोण - संदर्भ संदर्भ है, इसलिए संदर्भ के अनुसार स्वयं को पारित करने की आवश्यकता नहीं है। इसके साथ स्पष्ट मुद्दा संदर्भ की प्रतिलिपि बना रहा है, जो कुछ संदर्भ-गिनती ओवरहेड का सुझाव देता है। shared_ptr उदाहरण की प्रतिलिपि बनाने से परहेज है, लेकिन बजाय कि संदर्भित ऑब्जेक्ट के लिए पहुँचता जिसका अर्थ बजाय अपसंदर्भन एक की दो परतों की जरूरत है -

void foo (shared_ptr<bar> p) 

दूसरा दृष्टिकोण स्थिरांक संदर्भ द्वारा shared_ptr पारित करने के लिए है।

void foo (const shared_ptr<bar> &p) 

प्रैक्टिस में, ये सैद्धांतिक ओवरहेड सामान्य रूप से तुच्छ और अप्रासंगिक होंगे। जो मुझे बताता है कि प्रत्येक व्यक्ति के लिए एक दृष्टिकोण या दूसरे को चुनने के बजाय, मुझे लगभग हमेशा कुछ मानक सम्मेलन का पालन करना चाहिए। जो सवाल की ओर जाता है ...

क्या कोई मानक सम्मेलन है जिसके लिए मुझे सामान्य रूप से चुनना चाहिए? यदि हां, तो पारंपरिक विकल्प कौन सा है?

संपादित - शायद उल्लेख के लायक - एक कारण पर विचार करने के एक पूर्व मौजूदा सम्मेलन है कि ज्यादातर वर्ग/struct उदाहरणों बल्कि मूल्य की तुलना में स्थिरांक-संदर्भ द्वारा पारित कर रहे हैं क्योंकि पास-दर-स्थिरांक-संदर्भ मामला है, और shared_ptr एक कक्षा है। बेशक यह हेवीवेट क्लास नहीं है (प्रतिलिपि की लागत छोटी है), इसलिए उस पुराने सम्मेलन के पीछे कारण लागू नहीं हो सकते हैं।

+0

पोस्ट करने से पहले मुझे एक संभावित डुप्लिकेट याद आया - http://stackoverflow.com/questions/5330793/shared-ptr-pass-by-value-vs-pass-by-reference - लेकिन यह किसी विशेष के लिए अधिक विशिष्ट हो सकता है एक सामान्य सम्मेलन के बजाय आवश्यकता। – Steve314

+1

¤ वैसे भी संभव माइक्रो-अक्षमताएं हैं, इसलिए * स्पष्टता * के लिए जाएं। मूल्य से गुजरें। कच्चे सूचक के लिए आप यही करेंगे, यानी यह स्थापित सम्मेलन है। कुछ और पाठक आश्चर्य क्यों करता है। कौन सा गलत होगा, अस्पष्ट। चीयर्स और एचटी।, –

+0

@ एएलएफ - मैं जो कहता हूं उसके बारे में सोच रहा हूं। एक प्रतिक्रिया मेरा संपादन है, लेकिन इसका मतलब यह नहीं है कि मैं असहमत हूं। एक कच्चे संदर्भ को भी संदर्भ द्वारा पारित नहीं किया जा सकता है (हालांकि कच्चे सूचक भी कर सकते हैं), इसलिए मुझे यकीन नहीं है कि "सम्मेलन" सही शब्द है, लेकिन एक अनिवार्य अभ्यास निश्चित रूप से पारंपरिक है। मुझे लगता है कि आपके पास एक बिंदु है, लेकिन मुझे अभी भी संदेह है - सी ++ में, जहां कॉन्स्ट्रेंस द्वारा संरचना/कक्षा के उदाहरणों को पारित करना आमतौर पर किया जाता है (दक्षता कारणों के लिए, लेकिन एक सम्मेलन के रूप में भी), इरादे के बारे में कुछ भी ऐसा करने के लिए कुछ भी करता है? शायद यह हो सकता है, लेकिन शायद किसी भी स्पष्ट/निश्चित तरीके से नहीं। – Steve314

उत्तर

13

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

अधिक जानकारी के लिए here देखें।


उदाहरण:

#include <memory> 
#include <iostream> 

std::shared_ptr<int> ptr(new int(42)); 

void foo(){ 
    ptr.reset(); 
} 

void bar(std::shared_ptr<int> const& p){ 
    foo(); 
    std::cout << *p; 
} 

int main(){ 
    bar(ptr); 
} 

यह नमक की एक चुटकी के साथ लिया जाना चाहिए। यह साबित करने के लिए अनुकूलित किया जा सकता है कि किसी भी प्रकार को कभी भी कॉन्स्ट-रेफरेंस द्वारा पारित नहीं किया जाना चाहिए - उदाहरण के लिए http://ideone.com/1IYyC देखें, जो बेंजामिन लिंडली ने टिप्पणियों में बताया।

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

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

+0

पॉइंटर द्वारा प्रबंधित ऑब्जेक्ट के फ़ंक्शन को कॉल करने से पॉइंटर रीसेट हो सकता है, या पॉइंटर पर कोई प्रभाव पड़ सकता है? या मैं यह सही नहीं पढ़ रहा हूँ? –

+0

शायद एक उदाहरण? ऑब्जेक्ट कैसे और कैसे रीसेट करता है? – UncleBens

+0

@ बेंजामिन: एक ऑब्जेक्ट जिसे हमेशा 'shared_ptr' द्वारा प्रबंधित किया जाता है ('enable_shared_from_this' और सामान से विरासत) उस माता-पिता को वापस कॉल कर सकता है जो इसे प्रबंधित करता है और जो इसे रीसेट कर सकता है .. या ऐसा कुछ। यह बहुत समय पहले नहीं था कि मैंने पाठ पढ़ा जहां एक अच्छा स्पष्टीकरण के साथ यह सटीक कारण दिया गया था, अगर केवल मुझे यह मिल सके ... – Xeo

-1

क्या @Xeo कहा करने के लिए एक उदाहरण:

void foo(shared_ptr<bar> &p) 
{ 
    p.reset(); // ref_count == 0; memory is freed. 
} 

shared_ptr<bar> p(new bar); // ref_count == 1 
foo(p); 

यह const shared_ptr<bar> &p के लिए नहीं होता है।

+0

मुझे लगता है कि आप एक 'p.reset() 'या ऐसा कुछ खो रहे हैं? – Xeo

+1

फ़ंक्शन के अंदर 'shared_ptr'' const' है, आप उस पर 'रीसेट' नहीं कह सकते हैं। –

+0

उह ... ठीक है तो। :) –

0

यदि ऑब्जेक्ट में हेरफेर करने वाला फ़ंक्शन किसी स्मार्ट पॉइंटर में मौजूद है तो यह प्रासंगिक नहीं होना चाहिए। इसे T& स्वीकार करना चाहिए। मूल्यों में हेरफेर करने वाले नि: शुल्क कार्यों को कुछ लोगों द्वारा खराब शैली माना जाता है। ऑब्जेक्ट को कॉन्स के संदर्भ में लेना और एक नया मान लौटना क्लीनर हो सकता है।

0

मैं विचार है कि कहीं न कहीं ऊपर कॉल स्टैक किसी shared_ptr के प्रतिलिपि पकड़े जाना चाहिए और इसलिए अपने जीवन अपने पूरे निष्पादन के लिए गारंटी है के आधार पर स्थिरांक & से गुजर रहा है।

मामले कि आप एक अलग धागे पर क्रियान्वित कर रहे हैं, आप एक प्रति की जरूरत है - और उस बात किसी को भी कि भंडार shared_ptr (न सिर्फ उनकी विधि की अवधि के लिए इसे इस्तेमाल करता है) एक प्रतिलिपि संग्रहीत करने की आवश्यकता के लिए, संदर्भ नहीं

और, अब मैंने लिखा है कि मैं जाऊंगा और पढ़ूंगा कि लोग विपरीत मानसिकता का समर्थन क्यों कर रहे हैं।

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