2010-04-11 29 views
19

से लौटने वाली ऑब्जेक्ट मैं अब वास्तव में उलझन में हूं कि फ़ंक्शन से ऑब्जेक्ट को वापस करने के लिए किस प्रकार और किस विधि का उपयोग करना है। मुझे दी गई आवश्यकताओं के समाधान पर कुछ प्रतिक्रिया चाहिए।फ़ंक्शन

परिदृश्य ए: लौटाया गया ऑब्जेक्ट एक चर में संग्रहीत किया जाना चाहिए जिसे अपने जीवनकाल में संशोधित करने की आवश्यकता नहीं है।

someMethod() { 
const Foo& l_Foo = someClassPInstance->GetFoo(); 
//... 
} 

Scneraio बी:: इस प्रकार,

const Foo SomeClass::GetFoo() { 
return Foo(); 
} 

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

void SomeClass::GetFoo(Foo& a_Foo_ref) { 
    a_Foo_ref = Foo(); 
    } 

लागू के रूप में: कहते हैं कि चलो कि फू एक डिफ़ॉल्ट निर्माता नहीं कर सकते हैं:

someMethod() { 
Foo l_Foo; 
someClassPInstance->GetFoo(l_Foo); 
//... 
} 

मैं यहाँ एक सवाल है। तो फिर तुम इस स्थिति में उस के साथ सौदा होगा, क्योंकि हम नहीं कर सकते अब और इस बारे में:

Foo l_Foo 

परिदृश्य सी:

Foo SomeClass::GetFoo() { 
return Foo(); 
} 

लागू के रूप में:

someMethod() { 
Foo l_Foo = someClassPInstance->GetFoo(); 
//... 
} 

मुझे लगता है कि यह अनुशंसित दृष्टिकोण नहीं है क्योंकि यह अतिरिक्त अस्थायी निर्माण करेगा।

आपको क्या लगता है? इसके अलावा, क्या आप इसके बजाय इसे संभालने का एक बेहतर तरीका सुझाते हैं?

+2

http://en.wikipedia.org/wiki/Return_value_optimization – vladr

+0

परिदृश्य ए ठीक है लेकिन वास्तव में सी में कोई सुधार नहीं है।मैं तब तक सी का उपयोग करता हूं जब तक फू का डिफॉल्ट कन्स्ट्रक्टर "तेज़" न हो, फू की प्रतिलिपि ctor "धीमी" है और आप अनावश्यक प्रतियों को दूर करने के लिए पर्याप्त स्मार्ट होने वाले संकलक पर भरोसा नहीं करना चाहते हैं, जिसमें बी बी भी स्वीकार्य है। – sellibitze

+0

ध्यान दें कि 'a_Foo_ref = Foo();' ऑब्जेक्ट बनाता है और कॉपी करता है। यह पिछले परिदृश्य के समतुल्य है – Anycorn

उत्तर

16

पहले, आइए चीजें हैं जो यहाँ भूमिका निभाते हैं पर गौर करते हैं:

एक अस्थायी की (क) का विस्तार जीवन जब यह एक संदर्भ प्रारंभ करने में प्रयोग किया जाता है - मैं आंद्रेई Anexandrescu द्वारा this publication में इसके बारे में सीखा है। फिर, यह अजीब लेकिन उपयोगी लगता है:

class Foo { ... } 

Foo GetFoo() { return Foo(); } // returning temporary 

void UseGetFoo() 
{ 
    Foo const & foo = GetFoo(); 
    // ... rock'n'roll ... 
    foo.StillHere(); 
} 

शासन का कहना है कि जब एक संदर्भ के लिए एक अस्थायी साथ आरंभ नहीं हो जाता, के अस्थायी जीवन भर जब तक संदर्भ दायरे से बाहर चला जाता है बढ़ा दिया गया है। (this reply उद्धरण कैनन)

(ख) वापसी मूल्य अनुकूलन - (wikipedia) - दो प्रतियां स्थानीय -> वापसी मान -> स्थानीय परिस्थितियों में लोप हो सकता है। यह एक आश्चर्यजनक नियम है, क्योंकि यह संकलक को देखने योग्य व्यवहार को बदलने की अनुमति देता है, लेकिन उपयोगी है।

वहां आपके पास है। सी ++ - अजीब लेकिन उपयोगी।


तो अपने परिदृश्य को देखकर

परिदृश्य एक: आप एक अस्थायी लौट रहे हैं, और एक संदर्भ के लिए यह बाँध - के अस्थायी जीवन l_Foo के जीवनकाल के लिए बढ़ा दिया गया है।

ध्यान दें कि यह काम नहीं करेगा अगर GetFoo अस्थायी के बजाय संदर्भ वापस करेगा।

परिदृश्य बी: काम करता है, को छोड़कर यह है कि बलों एक निर्माण-निर्माण-कॉपी-चक्र (जो एक निर्माण की तुलना में बहुत अधिक महंगा हो सकता है), और समस्या आप एक डिफ़ॉल्ट निर्माता की आवश्यकता होती है के बारे में उल्लेख है।

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

परिदृश्य सी: अस्थायी की प्रतियां संकलक (आरवीओ नियम के अनुसार) द्वारा छोड़ी जा सकती हैं। दुर्भाग्यवश कोई गारंटी नहीं है - लेकिन आधुनिक कंपाइलर आरवीओ को लागू करते हैं।

Rvalue references सी ++ 0x में फू को संसाधन चोरी करने वाले कन्स्ट्रक्टर को लागू करने की अनुमति देता है जो न केवल प्रतियों के दमन की गारंटी देता है, बल्कि अन्य परिदृश्यों में भी काम करता है।

(मुझे शक है एक संकलक कि rvalue संदर्भ नहीं बल्कि RVO लागू करता है कि। हालांकि परिदृश्यों जहां RVO में लात नहीं कर सकते हैं।)


इस तरह एक सवाल जैसे स्मार्ट संकेत उल्लेख की आवश्यकता है, shared_ptr और unique_ptr (बाद वाला "सुरक्षित" auto_ptr) है। वे C++ 0x में भी हैं। वे वस्तुओं को बनाने के कार्यों के लिए एक वैकल्पिक पैटर्न प्रदान करते हैं।


+0

@ पीटर: उन लिंक के साथ इस तरह के एक विस्तृत प्रतिक्रिया के लिए धन्यवाद! मैं वास्तव में इसकी प्रशंसा करता हूँ। मैं इसे कुछ समय के लिए समझने की कोशिश कर रहा हूं, इसलिए परिदृश्य ए से परिचित हूं। मुझे परिदृश्य बी के बारे में 1 प्रश्न था। मैं आमतौर पर बी का उपयोग करता हूं जब मुझे किसी ऑब्जेक्ट को संशोधित करना होता है और जब मुझे इसे GetFoo के अंदर बनाना नहीं होता है ()। अब, यह मानते हुए; जब हम 'Foo l_Foo कहते हैं; someClassPInstance-> GetFoo (l_Foo); ':: हम l_Foo का संदर्भ भेजते हैं, इस प्रकार यहां कोई अस्थायी नहीं है। और फिर, 'void SomeClass :: GetFoo (Foo & a_Foo_ref) {// ..} में बस कहें, मैं इसे संशोधित करता हूं और इसे नहीं बनाता। क्या आपको लगता है कि बी एक अच्छा विकल्प है – brainydexter

+0

इसके अलावा, मूल प्रश्न के लिए मेरी आखिरी टिप्पणी देखें। – brainydexter

+0

@brainydexter: हाँ, यह संदर्भ के लिए एक सामान्य उपयोग परिदृश्य है। इसके लिए कुछ दस्तावेज की आवश्यकता है (क्या यह बाहर या अंदर/बाहर आदि है)। संदर्भ के लिए धन्यवाद, मैं एक लिंक के साथ अद्यतन करूँगा। --- मैंने हाल ही में रावल संदर्भों के साथ खिलवाड़ किया है - यह भी मेरे लिए एक अच्छा अभ्यास था। – peterchen

4

तीन परिदृश्यों में से, संख्या 3 आदर्श पद्धति है, और जिसे आप शायद उपयोग करना चाहिए। आप अतिरिक्त प्रतियों के लिए भुगतान नहीं करेंगे क्योंकि यदि संभव हो तो प्रतिलिपि से बचने के लिए संकलक copy elision का उपयोग करने के लिए स्वतंत्र है।

सिक्योरियो ए गलत है। आप एक अस्थायी संदर्भ के साथ समाप्त होते हैं जो फ़ंक्शन कॉल युक्त कथन समाप्त होने पर नष्ट हो जाता है। ठीक है, परिदृश्य एक गलत नहीं है, लेकिन आप अभी भी उपयोग करना चाहिए परिदृश्य सी

Secnario बी बस ठीक काम करता है, लेकिन:

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

फू के पास एक डिफ़ॉल्ट कन्स्ट्रक्टर होना चाहिए। यहां तक ​​कि यदि आप इसे एक नहीं देते हैं, तो संकलक आपके लिए जरूरी है। मान लें कि आप private कन्स्ट्रक्टर घोषित करते हैं, इस कॉलिंग विधि का उपयोग करने का कोई तरीका नहीं है। आपको या तो Foo डिफ़ॉल्ट कन्स्ट्रक्टेबल बनाने या सिक्योरियो सी का उपयोग करने की आवश्यकता है।

+1

'const Foo SomeClass :: GetFoo() ':: परिदृश्य ए :: मैं यहां अस्थायी के संदर्भ को वापस नहीं कर रहा हूं .. – brainydexter

+0

@brainydexter: ओह .. आप सही हैं। हालांकि, मुझे विश्वास है कि यह अभी भी गलत है। मैं 100% निश्चित नहीं हूं, लेकिन मुझे विश्वास है कि इसका संदर्भ होने के बावजूद अस्थायी नष्ट हो जाएगा। आपको वास्तविक वस्तु को चारों ओर रखना होगा। –

+1

परिदृश्य ए ठीक है लेकिन वास्तव में सी में कोई सुधार नहीं है। सी ++ में एक विशेष नियम है जो इस मामले में अस्थायी वस्तु का जीवनकाल बढ़ाता है। – sellibitze