2013-01-23 40 views
5

जैसा कि मैं अस्थायी समझता हूं, निम्नलिखित कोड काम करना चाहिए, लेकिन ऐसा नहीं है।सी ++ अस्थायी - "शुद्ध वर्चुअल विधि"

struct base 
{ 
    virtual~base() {} 
    virtual void virt()const=0; 
}; 
struct derived:public base 
{ 
    virtual void virt()const {} 
}; 

const base& foo() {return derived();} 

int main() 
{ 
    foo().virt(); 
    return 0; 
} 

virt के लिए कॉल() एक "शुद्ध आभासी समारोह कहा जाता है" त्रुटि दिखाता है। वह क्यों है, और मुझे क्या करना चाहिए?

उत्तर

5

ऐसा लगता है कि आप अस्थायी जीवनकाल को बढ़ाने के लिए const संदर्भ की अपेक्षा कर रहे हैं। ऐसी कुछ स्थितियां हैं जहां यह नहीं होती है। उन स्थितियों में से एक है जब एक अस्थायी लौटा रहा है:

दूसरा संदर्भ [जिसमें temporaries पूर्ण अभिव्यक्ति के अंत से एक अलग बिंदु पर नष्ट कर रहे हैं] जब एक संदर्भ के लिए एक अस्थायी करने के लिए बाध्य किया जाता है। अस्थायी जो संदर्भ बाध्य है या अस्थायी है कि एक subobject संदर्भ को छोड़कर संदर्भ के जीवनकाल के लिए बनी ही है जो करने के लिए की पूरी वस्तु है:

[...]

  • फ़ंक्शन रिटर्न स्टेटमेंट (6.6.3) में लौटाए गए मूल्य के अस्थायी बाध्यता का जीवनकाल विस्तारित नहीं होता है; रिटर्न स्टेटमेंट में पूर्ण अभिव्यक्ति के अंत में अस्थायी नष्ट हो जाता है।

के बाद वस्तु foo() द्वारा लौटाए के एक सदस्य फ़ंक्शन को कॉल एक lvalue करने वाली rvalue रूपांतरण की जरूरत होगी और वस्तु अमान्य (प्रकार base से प्राप्त नहीं) है, तो आप अपरिभाषित व्यवहार मिलता है:

यदि ऑब्जेक्ट जिस पर glvalue संदर्भित करता है वह T प्रकार का ऑब्जेक्ट नहीं है और T से व्युत्पन्न प्रकार का ऑब्जेक्ट नहीं है, या यदि ऑब्जेक्ट अनियंत्रित है, तो इस प्रोग्राम को जरूरी एक प्रोग्राम में अपरिभाषित व्यवहार है।

8

आप को नष्ट कर रहे अस्थायी के संदर्भ को वापस कर रहे हैं, जब कथन के अंत में फ़ंक्शन समाप्त होता है और आपको अपरिभाषित व्यवहार मिलता है।

आप अस्थायी के किसी भी प्रकार का संदर्भ वापस नहीं कर सकते हैं और यदि आप base मूल्य से वापस लौटते हैं तो आपको स्लाइसिंग मिल जाएगी, इसलिए यदि आप वास्तव में यह काम करना चाहते हैं, तो आपको std::unique_ptr<base> वापस करना चाहिए।

+0

बिल्कुल, क्योंकि आभासी तालिका भी साफ हो जाएगी ... इसलिए संदेश। –

+2

@DougT .: "अपरिभाषित व्यवहार" में कोई "कारण" नहीं है। (इसके अलावा, आभासी * टेबल * कभी भी "साफ नहीं हो जाता"।) –

+0

लेकिन पूर्ण अभिव्यक्ति के अंत में अस्थायी वस्तु को नष्ट नहीं किया जाना चाहिए, जो बाद में() वापस आ गया है? – Dave

3

मुझे नहीं लगता कि आप इस तरह की वस्तुओं के संदर्भ वापस कर सकते हैं। व्युत्पन्न() उदाहरण foo() रिटर्न जैसे ही दायरे से बाहर हो जाता है।

base *foo() { return new derived(); } 

और

foo()->virt(); 

काम करना चाहिए है।

+3

यह काम करना चाहिए, लेकिन हमें इन दिनों के आसपास कच्चे पॉइंटर्स को पास करने की आवश्यकता नहीं है ... –

+2

सुनिश्चित करें, अगर आप shared_ptr <> या पसंद का उपयोग करना चाहते हैं, तो आपको वास्तविक कोड में यही करना चाहिए। हालांकि मेरा मुद्दा मूल रूप से है कि हमें इस काम के लिए ढेर पर ऑब्जेक्ट आवंटित करने की आवश्यकता है, उस तथ्य को पॉइंटर-डर के ढेर के नीचे क्यों छुपाएं? – Johannes

+1

@ जोहान्स: क्योंकि यह सिर्फ मेमोरी लीक के लिए पूछ रहा है। स्मार्ट पॉइंटर्स मानक पुस्तकालय में हैं - उनका उपयोग करें! : -] – ildjarn

0

कॉल के दौरान कोई ऑब्जेक्ट नहीं है, स्थानीय ऑब्जेक्ट हटा दिया गया था। देखने के लिए कोई vtable नहीं होगा। आज़माएं:

base& foo() { return *new derived(); } 
+0

कॉलर को कैसे पता चलता है कि उसे स्मृति मुक्त करना है? –

0

आपकी अस्थायी 'व्युत्पन्न()' ऑब्जेक्ट को स्टैक पर आवंटित किया गया है। ऑब्जेक्ट अप-कास्टिंग के साथ इसका कुछ संबंध हो सकता है।

आधार आधार & foo() {व्युत्पन्न * डी = नया व्युत्पन्न(); वापसी * ​​डी; }

मेरे लिए ठीक काम करता है।

+1

स्मृति लेना _not_ ठीक काम कर रहा है। ; -] – ildjarn

+0

निश्चित- पकड़ने के लिए धन्यवाद। मैं एक बूस्ट का उपयोग कर सकता था :: shared_ptr <> – Arcturus

0

इस के लिए समस्या टुकड़ा बदलें:

class A { 
public: 
    const base &foo() { return d; } 
private: 
    derived d; 
}; 

इस तरह ली गई वस्तु के जीवनकाल एक के जीवन के रूप में रूप में लंबे समय है, और किसी भी समस्याओं कभी नहीं होगा।

+0

क्या होगा अगर मैंने फ़ंक्शन 'बार' के ढेर पर ए बनाया और 'bar' से संदर्भ 'd' को वापस कर दिया? –