2012-08-10 10 views
15

संभव डुप्लिकेट:
Is it better in C++ to pass by value or pass by constant reference?क्यों आप C++ मूल्य द्वारा एक वस्तु से होकर गुजरेगा

मैं सी ++ में मूल्य, सूचक और संदर्भ से गुजर के अंतर के बारे में पता कर रहा हूँ, और मैं लगभग + प्रोग्रामिंग त्रुटि होने के लिए C++ में मान (गुणांक संदर्भ के बजाय) द्वारा वस्तुओं को गुजरने पर विचार करता हूं।

void foo(Obj o); ... // Bad 

void foo(const Obj &o); ... // Better 

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

लेकिन, निश्चित रूप से यह ऐसी चीज है जो संकलक निर्धारित करने के लिए बनाई गई हैं?

क्यों सी ++ वास्तव में को मूल्य से गुजरता है और कॉन्स्ट संदर्भ द्वारा पास किया जाता है, और - क्या कंपेलरों को उचित रूप से कॉल को (और से) एक कॉन्स्ट संदर्भ में परिवर्तित करने की अनुमति है?

(वहाँ सी के 100s ++, सम्मेलन सवाल बुला के बीच (माना) मूल्य और संदर्भ मतभेदों के बारे में पूछ होने लगते हैं - लेकिन मैं नहीं एक है कि पूछा, "? क्यों" मिल सकता है।)

+2

हर बार जब आपको किसी प्रतिलिपि की आवश्यकता होती है तो क्या होगा? 'ओबीजे ओ 2 (ओ);' पहली पंक्ति के रूप में जोड़ें? यह बल्कि व्यर्थ लगता है। इसके अलावा, semantics ले जाएँ। – delnan

+0

@ डेलनान - धन्यवाद। मैं आमतौर पर वर्णन करता हूं जैसा कि आप वर्णन करते हैं, क्योंकि मुझे लगता है कि यह फ़ंक्शन का कार्यान्वयन विवरण है जो इसके बाहरी हस्ताक्षर का हिस्सा नहीं बनना चाहिए। – Roddy

+0

@ नीमो। हाँ धन्यवाद। बंद करने के लिए वोट दिया! अफसोस की बात है कि हाइव दिमाग एसओ के अंतर्निहित एक बेहतर खोज उपकरण है ... – Roddy

उत्तर

4

हैं मैं मूल को प्रभावित किए बिना समारोह के भीतर वस्तु के लिए काम करने के लिए चाहता था, मैं मान द्वारा पारित होगा:

A minus(A b){ 
    b.val=-b.val; 
    return b; 
} 
1

तो वस्तु परिवर्तनशील है, मूल्य से गुजर रिसीवर अपनी एक प्रतिलिपि का उपयोग करने और जहां देता समझदार परिवर्तन , कॉलर की प्रति को प्रभावित किए बिना - हमेशा यह मानते हुए कि यह पर्याप्त गहरी प्रति है।

यह कुछ बहु थ्रेडेड परिस्थितियों में सोच को सरल बना सकता है।

10

मूल्य से गुजरने का सवाल मानक के विभिन्न संस्करणों के साथ अलग-अलग उत्तरों के अलग-अलग उत्तरों के मुकाबले बेहतर हो सकता है।

अच्छे पुराने सी ++ 03 में, और कुछ साल पहले, सिफारिश ऐसी किसी भी चीज को पारित करने के लिए होगी जो कॉन्स्ट संदर्भ द्वारा किसी रजिस्टर में फिट न हो। इस मामले में, इस सवाल का जवाब होगा:

  • Obj क्योंकि एक रजिस्टर में और मूल्य से गुजर रहा है और मूल्य से गुजर अधिक कुशल
सी ++ 03 में

फिर भी हो जाएगा फिट, पिछले वर्षों में (बेतुका यह कुछ लेख इस लगभग 10 साल पहले की सिफारिश की लगता है के रूप में है, लेकिन कोई वास्तविक आम सहमति नहीं थी),

  • समारोह की जरूरत है एक प्रतिलिपि बनाने के लिए, तो इंटरफ़ेस में ऐसा करने से प्रति संकलक की अनुमति देता है फॉर्म कॉपी-एलिजन यदि प्रतिलिपि का स्रोत अस्थायी है, तो यह अधिक कुशल हो सकता है।
rvalue संदर्भ के लिए नए सी ++ 11 मानक के अनुमोदन, और बढ़ती संकलक समर्थन के साथ

, कई मामलों में भी जब प्रतिलिपि elided नहीं किया जा सकता है, और फिर

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

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

1

सी ++ को वास्तव में मूल्य से गुजरने की आवश्यकता क्यों होती है और कॉन्स्ट संदर्भ द्वारा पास की जाती है, और - क्या कंपेलरों को उचित रूप से कॉल को (और से) एक कॉन्स्ट संदर्भ में परिवर्तित करने की अनुमति है?

मुझे पहले दूसरे का जवाब दें: कभी-कभी।

कंपाइलर्स को प्रतिलिपि में प्रतिलिपि बनाने की अनुमति है, लेकिन केवल तभी जब आप एक रावल्यू अस्थायी रूप से पास करते हैं। उदाहरण के लिए:

void foo(Obj o); 

foo((Obj()))); //Extra set of parenthesis are needed to prevent Most Vexing Parse 

अस्थायी की नकल तर्क पैरामीटर में elided किया जा सकता है (यानी: कॉपी नहीं), संकलक की सुविधा पर)।

बहरहाल, यह प्रतिलिपि कभी नहीं elided किया जाएगा:

Obj a; 
foo(a); 

अब, पहले करने के लिए पर। सी ++ दोनों की जरूरत है क्योंकि आप दोनों अलग-अलग चीजों के लिए उपयोग करना चाह सकते हैं। मूल्य से गुजरना स्वामित्व स्थानांतरित करने के लिए उपयोगी है; यह सी ++ 11 में अधिक महत्वपूर्ण है जहां हम प्रतिलिपि वस्तुओं की बजाय स्थानांतरित कर सकते हैं।

+0

धन्यवाद। "मूल्य से गुजरना स्वामित्व स्थानांतरित करने के लिए उपयोगी है" क्या आप थोड़ा सा विस्तार कर सकते हैं? "वांछित गति? पास मूल्य" लेख के लिए – Roddy

3

प्रतिलिपि स्वैप मुहावरे एक संकलक उत्पन्न प्रति प्राप्त करने के लिए मूल्य द्वारा पैस का उपयोग करता है।

MyClass& operator=(MyClass value) // pass by value to generate copy 
{ 
    value.swap(*this);   // Now do the swap part. 
    return *this; 
} 

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

MyClass a; 
// Some code 
a = MyClass(); // reset the value of a 
       // compiler can easily elide this copy. 
6

निश्चित रूप से एक कारण सी ++ पारित-दर-मूल्य है, क्योंकि यह यह सी से विरासत में मिली, और हटाने कि छोटे लाभ के लिए कोड को तोड़ सकते थे है।

दूसरा, जैसा कि आप नोट करते हैं, मूल्य के आधार पर संदर्भित छोटे से कम प्रकार के लिए कम कुशल होगा।

void foo(const Obj& obj) 
{ 
    if(very_rare_check()) return; 

    Obj obj_copy(obj); 
    obj_copy.do_work(); 
} 

इस मामले ध्यान दें कि आप एक प्रति के लिए मजबूर कर रहे हैं में: यदि आप एक समारोह है कि किसी कारण के लिए अपने तर्क की एक प्रति की जरूरत है

एक और कम स्पष्ट मामला तथापि है। लेकिन लगता है कि यदि आप किसी अन्य समारोह है कि मूल्य से रिटर्न का परिणाम के साथ इस समारोह फोन:

Obj bar() { return Obj(parameters); } 

और thusly इसे कहते: अब foo(bar());

जब आप स्थिरांक संदर्भ संस्करण का उपयोग, संकलक दो बनाने खत्म हो जाएगा ऑब्जेक्ट्स: foo में अस्थायी, और प्रतिलिपि। यदि आप मूल्य से गुजरते हैं तो संकलक सभी अस्थायी को foo के उप-मान पैरामीटर द्वारा उपयोग किए गए स्थान पर अनुकूलित कर सकता है।

इस बारे में एक बड़ा लेख है और http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

अंत में विहित रास्ता में सामान्य रूप में अर्थ विज्ञान के लिए कदम कुछ ऑपरेटरों को लागू करने का प्रयोग है पारित-दर-मूल्य ऑपरेटर अंदर प्रतियां से बचने के लिए:

Obj operator+(Obj left, const Obj& right) 
{ 
    return left += right; 
} 

ध्यान दें कि यह कैसे संकलक को कॉपीर या अस्थायी ऑब्जेक्ट को ऑपरेटर के कोड के भीतर मजबूर करने के बजाय पैरामीटर में कॉपी उत्पन्न करने देता है।

+0

+1 –

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