2012-03-06 33 views
5

उदाहरण के लिए इस समारोह इस तरह परिभाषित च:आप एक स्थानीय चर के संदर्भ में एक फ़ंक्शन क्यों लौटा सकते हैं और अस्थायी चर के लिए नहीं? C++

int f(int x){return x;} 

जैसा कि आप जानते तुम नहीं कर सकते यह अस्थायी पूर्णांक के लिए एक संदर्भ में निर्दिष्ट करें:

int& rf=f(2);// this will give an error 

लेकिन अगर मैं इस तरह मेरी समारोह नए सिरे से परिभाषित च :

int& f(int x){return x;} 
f(2);// so now f(2) is a reference of x, which has been destroyed 

तो मेरा सवाल यह है कि: कंपाइलर आपको एक अस्थायी संदर्भ कैसे नहीं दे सकता ओरीरी जो स्टेटमेंट के बाद नष्ट हो जाएगी (पहला मामला int)। और दूसरी ओर यह आपको एक संदर्भ f (2) से x बनाने देता है जबकि संकलक जानता है कि यह return के बाद नष्ट हो जाएगा।

+1

यह यूबी है (ठीक है, संदर्भ का उपयोग, वैसे भी) और कोई भी सील कंपाइलर आपको इसके बारे में चेतावनी देगा। –

उत्तर

7

एक स्थानीय के लिए एक संदर्भ रिटर्निंग है हो सकता है कुछ है कि मुश्किल या असंभव संकलक का पता लगाने के लिए किया जा सकता है। उदाहरण के लिए:

int & f() 
{ 
    int x; 
    extern int & g(int & x); 

    // Does this return a reference to "x"? 
    // The compiler has no way to tell. 
    return g(x); 
} 

यहां तक ​​कि बाहरी कार्यों बुला बिना, यह अभी भी बताने के लिए है कि क्या लौटे संदर्भ एक स्थानीय करने के लिए है एक जटिल प्रोग्राम प्रवाह का विश्लेषण करने के लिए मुश्किल हो सकता है; निदान करने के लिए "सरल पर्याप्त" के रूप में परिभाषित करने की कोशिश करने के बजाय, मानक को नैदानिक ​​की आवश्यकता नहीं होती है - यह केवल यह कहता है कि यह अपरिभाषित व्यवहार देता है। एक अच्छे कंपाइलर को कम से कम सरल मामलों में चेतावनी देना चाहिए।

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

1

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

int& f(int x) 
{ 
    return x; 
} 
0

यह संदर्भ द्वारा वापस जाने के लिए जब तक आप सुनिश्चित करें कि संदर्भ आप वापस लौट रहे हैं अभी भी कुछ वैध पर इंगित किया जाएगा रहे हैं एक अच्छा विचार नहीं है:

क्या गलत है वास्तव में समारोह परिभाषा है।

अन्यथा, अपरिभाषित व्यवहार की उम्मीद है।

के बाद से चर स्थानीय है, तो आप यह सुनिश्चित करें कि तेह संदर्भ अमान्य

+2

चूंकि चर स्थानीय है, इसलिए आप सुनिश्चित कर सकते हैं कि यह अमान्य है। –

1

आप अपने जीवनकाल को लंबे समय तक बढ़ाने के लिए अस्थायी रावल्यू को बांध सकते हैं। तो भाषा कोई विकल्प नहीं है, लेकिन यह अनुमति देने के लिए, भले ही वह अपरिभाषित व्यवहार है -

const int& rf=f(2); 
0

समस्या यह है कि अर्थ की दृष्टि से देखते ढेर पर एक चर के बीच कोई अंतर है, या ढेर आदि पर एक चर है। पहले उदाहरण में आपको एक आसान संकलन त्रुटि मिलती है, क्योंकि आप अस्थायी चर पर एक संदर्भ को बाध्य करने का प्रयास कर रहे हैं, जिसे भाषा द्वारा प्रतिबंधित किया जा सकता है।

+0

हाँ मैं समझता हूं कि यह दूसरे उदाहरण के लिए क्यों काम करता है? और आपने ढेर का उल्लेख क्यों किया, और मैंने ढेर के बारे में कुछ भी नहीं कहा – AlexDan

+0

@AbdessamadBond इसका उत्तर है कि आपका दूसरा उदाहरण क्यों काम नहीं करता है .. और मैंने ढेर का उल्लेख किया है, क्योंकि ढेर पर एक चर के संदर्भ को वापस करना है ठीक है (भले ही यह शायद खराब शैली हो)। अर्थात् ढेर पर एक चर के बीच कोई अंतर नहीं है और एक स्टैक पर है, जबकि चर और अस्थायी मान के बीच कोई अंतर है। – cooky451

1

अपना पहला कोड स्निपेट अस्वीकार करने के लिए, कंपाइलर सरल नियम लागू करता है जिसे आप सीधे अस्थायी संदर्भ में अस्थायी नहीं जोड़ सकते हैं।

दूसरे को अस्वीकार करने के लिए, कंपाइलर शायद एक नियम लागू कर सकता है जो return संदर्भ द्वारा लौटाए गए फ़ंक्शन का कथन स्वचालित चर का नाम नहीं हो सकता है (बाय-वैल्यू फ़ंक्शन पैरामीटर सहित)। यह मुझे एक काफी आसान नियम भी लगता है।

मुझे नहीं पता कि मानक क्यों निर्दिष्ट नहीं करता है कि ऐसा करने से बीमार हो गया है। मैं इसके लिए किसी भी वैध उपयोग के बारे में नहीं सोच सकता, लेकिन शायद पहले मानक के समय यह कुछ कार्यान्वयन या अन्य पर अत्यधिक बोझ पैदा करेगा। या शायद यह महसूस किया गया था कि यह केवल आधे फिक्स है और इसके साथ परेशान करने के लायक नहीं है (लटकने वाले संदर्भ बनाने के कई अन्य तरीके हैं, यह सिर्फ उनमें से एक को ब्लॉक करता है)।

मानक सामान्य रूप से मानक नहीं है क्योंकि आप एक अस्थायी के लिए एक गैर-कॉन्स संदर्भ बनाते हैं, यह है कि यह ठीक होने पर अवसर होते हैं। उदाहरण के लिए:

struct Foo { 
    static void set(Foo &f) { f.val = 0; } 
    int val; 
    int bar() { 
     set(*this); 
     return val; 
    } 
}; 

std::cout << Foo().bar() << "\n"; 

यहाँ Foo() एक अस्थायी है, और लाइन set(*this) एक गैर स्थिरांक संदर्भ के लिए यह बांधता है (लेकिन सीधे नहीं, यह एक lvalue अभिव्यक्ति *this कुछ समय लेकिन दूसरों कि एक अस्थायी को संदर्भित करता है का उपयोग करता है) । यहां कोई समस्या नहीं है, अस्थायी रूप से संदर्भ संदर्भित करता है। तो यह किसी भी अस्थायी रूप से किसी भी अस्थायी संदर्भ से किसी भी अस्थायी होने से रोकने के लिए भाषा के लिए अनावश्यक रूप से प्रतिबंधित होगा।