2012-07-31 14 views
5
struct A { 
    A(int) : i(new int(783)) { 
     std::cout << "a ctor" << std::endl; 
    } 

    A(const A& other) : i(new int(*(other.i))) { 
     std::cout << "a copy ctor" << std::endl; 
    } 

    ~A() { 
     std::cout << "a dtor" << std::endl; 
     delete i; 
    } 

    void get() { 
     std::cout << *i << std::endl; 
    } 

private: 
    int* i; 
}; 

const A& foo() { 
    return A(32); 
} 

const A& foo_2() { 
    return 6; 
} 

int main() 
{ 
    A a = foo(); 
    a.get(); 
} 

मुझे पता है, स्थानीय मानों के संदर्भ वापस करना बुरा है। लेकिन, दूसरी ओर, कॉन्स संदर्भ एक अस्थायी वस्तु जीवनकाल का विस्तार करना चाहिए।स्थानीय ऑब्जेक्ट को संदर्भित करने के संदर्भ में वास्तव में क्या होता है?

यह कोड एक यूबी आउटपुट उत्पन्न करता है। तो कोई जीवन विस्तार नहीं।

क्यों? मेरा मतलब है कि कोई व्यक्ति बता सकता है कि चरण-दर-चरण क्या हो रहा है?

मेरी तर्क श्रृंखला में गलती कहां है?

foo():

  1. एक (32) - ctor

  2. वापसी एक (32) - स्थानीय ऑब्जेक्ट में एक स्थिरांक संदर्भ बनाई गई है और

  3. एक एक दिया जाता है = foo(); - foo() लौटा मूल्य द्वारा प्रारंभ किया गया है, लौटाया गया मूल्य दायरे से बाहर चला जाता है (अभिव्यक्ति से बाहर) और नष्ट हो जाता है, लेकिन पहले ही प्रारंभ हो चुका है;

(लेकिन असल में नाशक प्रतिलिपि निर्माता से पहले कहा जाता है)

foo_2():

  1. वापसी 6 - ग्रुप ए के अस्थायी वस्तु परोक्ष इस वस्तु के लिए एक स्थिरांक संदर्भ बनाई गई है बनाया गया है (इसके जीवन का विस्तार) और

  2. ए = foo(); - foo() लौटा मूल्य द्वारा प्रारंभ किया गया है, लौटाया गया मूल्य दायरे से बाहर चला जाता है (अभिव्यक्ति से बाहर) और नष्ट हो जाता है, लेकिन पहले ही प्रारंभ हो चुका है;

(लेकिन असल में नाशक प्रतिलिपि निर्माता से पहले कहा जाता है)

+1

"कॉन्स्ट रेफरेंस को अस्थायी ऑब्जेक्ट आजीवन का विस्तार करना चाहिए" <- erm, जब ऑब्जेक्ट-आजीवन गैर-कॉन्स और कॉन्स संदर्भों की बात आती है तो यह बराबर होती है और * इसे * विस्तारित नहीं करती है। – Giel

+2

मुझे लगता है कि अलेक्जेंडर जीवनकाल को विस्तारित करने के मामले में बात कर रहा है: http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ – vmpstr

+1

@Giel: सं। संदर्भ संदर्भ ** ** अस्थायी वस्तु का जीवनकाल बढ़ा सकते हैं। जब अस्थायी लोगों के साथ काम करने की बात आती है तो कॉन्स्ट- और गैर-कॉन्स संदर्भ काफी भिन्न होते हैं। इस मामले में यह ओपी की अपेक्षा करने के लिए अलग-अलग काम करता है। – AnT

उत्तर

11

प्रत्येक विशिष्ट संदर्भ के लिए अस्थायी जीवन विस्तार के नियम स्पष्ट रूप से भाषा विनिर्देश में बाहर से लिखे गए हैं। और यह कहा गया है कि

12,2 अस्थायी वस्तुओं

5 सेकंड संदर्भ जब एक संदर्भ के लिए एक अस्थायी करने के लिए बाध्य किया जाता है। [...] फ़ंक्शन रिटर्न स्टेटमेंट (6.6.3) में लौटाए गए मान के लिए अस्थायी बाध्य कार्य पूरा होने तक जारी रहता है। [...]

फ़ंक्शन निकास के समय आपकी अस्थायी वस्तु नष्ट हो जाती है। प्राप्तकर्ता ऑब्जेक्ट की शुरूआत से पहले ऐसा होता है।

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

आपके foo और आपके foo_2 दोनों अनिर्धारित व्यवहार का उत्पादन करते हैं, अगर कोई लौटा संदर्भ का उपयोग करने का प्रयास करता है।

+0

लेकिन यदि "फंक्शन रिटर्न स्टेटमेंट (6.6.3) में लौटाए गए मूल्य के लिए अस्थायी बाध्य कार्य तब तक जारी रहता है जब तक कि फ़ंक्शन से बाहर नहीं निकलता है" shoudnt अस्थायी मान को foo_3() {return A (54);} में प्रारंभ करने से पहले नष्ट किया जा सकता है? – Alexander

+1

@Alexander - नहीं, 'एक foo_3() 'मान की एक प्रति देता है। प्रतिलिपि मूल्य समारोह के अंत में नष्ट नहीं होता है। जब आप कोई संदर्भ वापस करते हैं, तो संदर्भ अभी भी वहां है - यह अब और कुछ भी संदर्भित नहीं करता है। –

+0

मैं देखता हूं .. लेकिन फिर कॉपी करें ctor अभिव्यक्ति में 2 बार कहा जाना चाहिए a = foo_3(); पहली बार जब लौटने का मूल्य अस्थायी स्थानीय से कॉपी किया जाता है और दूसरी बार ए शुरू होता है। लेकिन इसे केवल एक बार बुलाया जाता है। या यह सिर्फ एक अनुकूलन है? – Alexander

3

आप "फ़ंक्शन से बाहर निकलने तक" गलत तरीके से गलत हैं। क्या तुम सच में foo परे एक वस्तु के जीवन का विस्तार करने के लिए एक स्थिरांक संदर्भ का उपयोग करना चाहते हैं, तो

A foo() { 
    return A(32); 
} 
int main() { 
    const A& a = foo(); 
} 

का उपयोग आप मूल्य द्वारा fooसे लौटना चाहिए, और फिर एक स्थिरांक संदर्भ का उपयोग वापसी मान संदर्भित करने के लिए, अगर आप जिस चीज की अपेक्षा करते हैं उसमें चीजें विस्तारित करना चाहते हैं।

जैसा कि @AndreyT ने कहा है, ऑब्जेक्ट उस कार्य में नष्ट हो गया है जिसमें const & है। आप अपने वस्तु foo परे जीवित रहने के लिए चाहते हैं, और इसलिए आप चाहिए const & (या &) foo में या foo की वापसी प्रकार में कहीं भी नहींconst & का पहला उल्लेख main में होना चाहिए, क्योंकि वह कार्य है जिसे वस्तु को जीवित रखना चाहिए।

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