2008-11-09 14 views
8

E.g लौटने के लिए अधिक सक्षम है।क्या यह एक कॉन्स्ट संदर्भ

क्या इन से बाहर सबसे अच्छा है:

std::string f() {} 

या

const std::string& f() {} 
+0

मैंने कुछ हफ्ते पहले लगभग एक समान प्रश्न पूछा: http://stackoverflow.com/questions/134731/returning-a-const-reference-to-an-object-instead-of-a-copy – Rob

+0

काफी नहीं; आपके पास एक सदस्य के संदर्भ को वापस करना शामिल है। यह कई मामलों में तर्कसंगत रूप से सुरक्षित है (जब तक कि संदर्भ वस्तु को जल्द से जल्द नष्ट नहीं किया जाता है), लेकिन यह सवाल अधिक सामान्य है। :-) –

उत्तर

2

आप एक ऐसा वैरिएबल समारोह तो आप मुद्दों के साथ अंत करने के लिए (जा रहे हैं करने के लिए स्थानीय है के लिए एक संदर्भ वापस करते हैं कंपाइलर और इसकी सेटिंग्स के आधार पर)।

यदि आप किसी ऐसे उदाहरण के संदर्भ को वापस लौटते हैं जो फ़ंक्शन लौटाता है तब भी दायरे में है तो यह तेज़ होगा, क्योंकि स्ट्रिंग की कोई प्रति नहीं बनाई जा रही है।

तो उत्तरार्द्ध अधिक कुशल (तकनीकी रूप से) है लेकिन आप जो संदर्भ वापस लेते हैं उसके आधार पर अपेक्षित कार्य नहीं कर सकते हैं।

+0

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

+0

आरवीओ और एनआरवीओ केवल कंपाइलर अनुकूलन हैं जो तब होता है जब फ़ंक्शन किसी ऑब्जेक्ट को वापस करता है ... –

30

एक फ़ंक्शन कभी भी स्थानीय ऑब्जेक्ट/चर के संदर्भ में को वापस नहीं करना चाहिए क्योंकि ऐसी वस्तुएं दायरे से बाहर निकलती हैं और फ़ंक्शन लौटते समय नष्ट हो जाती हैं।

अलग-अलग फ़ंक्शन किसी ऑब्जेक्ट के लिए एक कॉन्स्ट या गैर कॉन्स्ट संदर्भ वापस कर सकता है जिसका दायरा फ़ंक्शन संदर्भ द्वारा सीमित नहीं है।

std::ostream & operator<<(std::ostream &out, const object &obj) 
{ 
    out << obj.data(); 
    return out; 
} 

दुर्भाग्य से लौटने-दर-मूल्य इसके प्रदर्शन को दोष यह है: विशिष्ट उदाहरण एक कस्टम operator<< है। जैसा कि क्रिस ने उल्लेख किया है, मूल्य से किसी ऑब्जेक्ट को वापस करने से अस्थायी वस्तु की प्रतिलिपि होती है और इसके बाद के विनाश होते हैं। प्रतिलिपि या तो कॉपी कन्स्ट्रक्टर या ऑपरेटर = के मेरे साधन रखती है। इन अक्षमता से बचने के लिए स्मार्ट कंपेलर आरवीओ या एनआरवीओ अनुकूलन लागू कर सकते हैं, लेकिन ऐसे मामले हैं जिनमें वे नहीं कर सकते - एकाधिक रिटर्न।

आगामी C++ 0x मानक, जीएनयू जीसीसी-4.3 में आंशिक रूप से उपलब्ध है, rvalue संदर्भ [& &] कि एक rvalue संदर्भ से एक lvalue भेद करने के लिए इस्तेमाल किया जा सकता परिचय देता है। इसके माध्यम से चालक को कार्यान्वित करना संभव है, ऑब्जेक्ट को आंशिक रूप से कॉपी कन्स्ट्रक्टर की लागत से बचने और अस्थायी के विनाशक से बचने के लिए उपयोगी है।

चालक कन्स्ट्रक्टर मूल रूप से क्रिस द्वारा सुझाए गए लेख http://www.ddj.com/database/184403855 लेख में एंड्रयू ने कल्पना की थी।

एक चाल निर्माता निम्नलिखित हस्ताक्षर हैं:

// move constructor 
object(object && obj) 
{} 

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

object factory() 
{ 
    object obj; 
    return std::move(obj); 
} 

std :: चाल() एक वस्तु से एक rvalue संदर्भ देता है: एक ठेठ समारोह कारखाना उसके बाद निम्न प्रपत्र होगा। अंतिम लेकिन कम से कम नहीं, रचनाकारों को गैर-प्रतिलिपि वस्तुओं के रिटर्न-बाय-रावल्यू-संदर्भ की अनुमति दें।

+1

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

+0

ओपीएस, ठीक है .. ठीक करने के लिए धन्यवाद। –

16

मैं निकोला के उत्कृष्ट उत्तर में जोड़ना चाहता हूं। हां, आपको कभी भी एक खतरनाक संदर्भ नहीं देना चाहिए (उदा।

  1. वापसी-मूल्य अनुकूलन (RVO): एक स्थानीय वेरिएबल का संदर्भ), तथापि, वहाँ उन मामलों में प्रदर्शन में सुधार करने के लिए तीन उपयोगी तरीके हैं आप मूल्य से लौटने के लिए, लेकिन केवल एक return होने से नकल को खत्म बयान, जो स्पॉट पर वापसी मूल्य बनाता है। यहां उपयोग किए जाने वाले आरवीओ का एक उदाहरण दिया गया है: How can I tokenize a C++ string?

  2. नामित रिटर्न-वैल्यू ऑप्टिमाइज़ेशन (एनआरवीओ): आप मूल्य से वापस आते हैं, और फ़ंक्शन के शीर्ष पर पहले रिटर्न वैल्यू वैरिएबल घोषित करते हैं। सभी return कथन उस चर को वापस कर देते हैं। एनआरवीओ का समर्थन करने वाले कंपाइलर्स के साथ, उस चर को रिटर्न-वैल्यू स्लॉट में आवंटित किया जाता है, और वापसी पर कॉपी नहीं किया जाता है। उदाहरण के लिए,

    string 
    foobar() 
    { 
        string result; 
        // fill in "result" 
        return result; 
    } 
    
  3. एक shared_ptr या वापसी प्रकार के रूप में की तरह का उपयोग करें; यह आपकी वस्तु को ढेर के बजाय ढेर पर बनाने की आवश्यकता है। यह लटकती-संदर्भ समस्याओं को रोकता है जबकि अभी भी पूरे ऑब्जेक्ट की प्रतिलिपि बनाने की आवश्यकता नहीं होती है, केवल स्मार्ट पॉइंटर।

वैसे, मैं आरवीओ और एनआरवीओ के बारे में जानकारी के लिए क्रेडिट नहीं ले सकता; वे सीधे स्कॉट मेयर्स के More Effective C++ से बाहर आते हैं। चूंकि मेरे पास इस समय मेरे साथ पुस्तक नहीं है, इसलिए मेरे विवरण में कोई भी त्रुटि स्कॉट की नहीं है। :-)

+0

राइट क्रिस। अपना उत्तर पूरा करने के लिए मैं आपको 4 के रूप में उल्लेख करना चाहता हूं। चालक कन्स्ट्रक्टर जो आने वाले सी ++ 0x :-) –

+0

@ निकोल के रेवल्यू संदर्भ के माध्यम से पहले से ही उपलब्ध है: जैसा कि मैं सी के साथ भी नहीं हूं ++ 0x, मुझे लगता है कि आपको एक पोस्ट लिखना चाहिए जिसमें यह बताते हुए कि चालक कन्स्ट्रक्टर कैसे काम करता है, और मैं आपको ऊपर उठाऊंगा। :-) –

+0

मैं अपना उत्तर अपडेट करने जा रहा हूं :) –

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