2010-12-09 16 views
7
TestObject getObject(){ 
    TestObject a(5.0f); 
    return a; 
} 

int main(){ 
    TestObject a = getObject(); 
} 

क्या मैं यह कहकर सही हूं कि सी ++ में एक लौटे ऑब्जेक्ट में इसे नष्ट करने के रूप में बुलाया जाने वाला विनाशक नहीं होगा। क्या मेमोरी फंक्शन कॉल में ऑब्जेक्ट ले लिया गया है जो विनाशक को चलाने के बिना हटा दिया गया है?सी ++ ऑब्जेक्ट रिटर्न

ठीक एक विशिष्ट उदाहरण ..

#include <iostream> 

class Test{ 
public: 
Test(){}; 
~Test(){std::cout << "Goodbye cruel world\n";} 
}; 


Test getAnObject(){ 
Test a; 
return a; 
} 

int main(){ 
Test a = getAnObject(); 
} 

यदि मैं यह नाशक चलाने सिर्फ एक बार चलाया जाता है (getAnObject में स्थानीय वस्तु के लिए नहीं())। क्या मुझे लगता है कि यह हमेशा मामला होगा?

#include <iostream> 

class Test{ 
public: 
Test(){}; 
~Test(){std::cout << "Goodbye cruel world\n";} 
}; 


Test getAnObject(){ 
Test a; 
Test b; 
int i = 0; 
if (i){ 
    return a; 
}else{ 
    return b; 
} 
} 

int main(){ 
Test a = getAnObject(); 
} 

RVO गाइड इस परीक्षण getanobject में दोनों वस्तुओं पर नाशक रन है() और मुख्य कार्य में बाद। क्या यह एक ऐसा मामला है जहां मुझे निरंतर व्यवहार सुनिश्चित करने के लिए हमेशा तीन नियमों को लागू करना चाहिए?

+5

getObject एक int वापस करने के लिए प्रोटोटाइप है ... एक testObject नहीं। – Max

+0

मेरी गलती ओह। धन्यवाद। – Guest300000000

उत्तर

9

यदि मैं इसे चलाता हूं तो विनाशक केवल एक बार चलाया जाता है (स्थानीय ऑब्जेक्ट के लिए एनोबजेक्ट() में नहीं)।क्या मुझे लगता है कि यह हमेशा मामला होगा?

शुद्धता के लिए? नहीं दक्षता के लिए? हाँ। -ish

विस्तृत करने के लिए: सख्ती से बोलते हुए, स्थानीय ऑब्जेक्ट को फ़ंक्शन से लौटने पर कॉपी किया जाएगा। स्थानीय संग्रहण को स्थानीय ऑब्जेक्ट के विनाशक को बुलाकर साफ किया जाएगा।

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

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

दूसरी ओर, आप उचित रूप से सभी आधुनिक कंपाइलरों को यह अनुकूलन करने की उम्मीद कर सकते हैं जहां कहीं भी संभव हो। इसलिए आप (आमतौर पर) प्रदर्शन के दृष्टिकोण से इस अनुकूलन पर भरोसा कर सकते हैं।

+1

गलत। कार्यक्रम खराब गठित है, एक निदान की आवश्यकता है, और इसलिए व्यवहार वास्तव में अच्छी तरह परिभाषित है। – Yttrill

+0

@Yttrill: सुधार के लिए धन्यवाद। मुझे यकीन नहीं था कि निदान की आवश्यकता है या नहीं। –

3

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

चूंकि getObject() के वापसी मूल्य को तुरंत इस विशेष मामले में एक चर के लिए असाइन किया गया है, तो एक आधुनिक कंपाइलर शायद कम से कम एक प्रति ऑपरेशन को अनुकूलित करने में सक्षम होगा।

+0

'int getObject() 'int वापस करना होगा, मुझे लगता है कि –

+0

जरूरी नहीं है; आरवीओ के साथ अन्य लोगों ने कहा है कि इसे अनुकूलित किया जा सकता है। – tenfour

+1

@tenfour, मैं अनुकूलन के बारे में नहीं कह रहा था, मैं इस तथ्य को इंगित कर रहा था कि यह फ़ंक्शन 'int' लौटा रहा था, न कि 'TestObject' –

5

यह कार्यान्वयन आधारित है। इसे रिटर्न वैल्यू ऑप्टिमाइज़ेशन तकनीक के रूप में जाना जाता है। इस बारे में अधिक जानकारी के लिए देखें:

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

0

GetObject() की कॉपी हो जाएंगे और GetObject में बनाया मूल वस्तु समारोह बाहर निकलने पर नष्ट हो जाता है, लेकिन वापसी मूल्य अनुकूलन हो सकता है (पर निर्भर करता है आप जिस कंपाइलर का उपयोग कर रहे हैं)।

0

उदाहरण में बेमेल रिटर्न प्रकारों के अलावा, आप शायद return value optimization, या अधिक सामान्य, copy elision की तलाश कर रहे हैं। अगर मुझे सही याद है, तो प्रतिलिपि elision नियम भी C++ मानक में निर्दिष्ट हैं, हालांकि कुछ हद तक अस्पष्ट है।

-1

getObject में, आप स्टैक पर TestObject बना रहे हैं, इसलिए वापसी मान अमान्य है। ढेर पर एक वस्तु बनाने के लिए, "नया" का उपयोग करें। मुझे विश्वास नहीं है कि जब विधवा का दायरा निकलता है तो विनाशक को बुलाया जाता है, मुझे लगता है कि ढेर पर स्मृति बस पुनः प्राप्त की जाती है।

+2

नहीं - यह गलत है। –

+0

@ कोनराड कॉपी कन्स्ट्रक्टर का आह्वान किया गया है? कृपया विस्तृत करें ... – flatline

+0

@flatline: निर्भर करता है। किसी भी तरह से, यह कोड बिल्कुल मान्य है। कॉपी कन्स्ट्रक्टर का आह्वान किया गया है या नहीं, इस पर निर्भर करता है कि संकलक कोड को अनुकूलित करेगा या नहीं। –

0

क्या स्मृति है कि फ़ंक्शन कॉल में ऑब्जेक्ट ले लिया गया ऑब्जेक्ट बस विनाशक को चलाने के बिना हटा दिया गया है?

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

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