2016-02-10 9 views
5

पहले उदाहरणइन दो रावण संदर्भ उदाहरणों के अलग-अलग व्यवहार क्यों हैं?

int a = 0; 
auto && b = ++a; 
++a; 
cout << a << b << endl; 

प्रिंट 22

दूसरा उदाहरण

int a = 0; 
auto && b = a++; 
++a; 
cout << a << b << endl; 

प्रिंट 20

प्रश्न: तीसरी पंक्ति में ++a पहले उदाहरण में क्यों b बढ़ता है, और दूसरे उदाहरण में ऐसा कोई व्यवहार क्यों नहीं है?

अद्यतन:New question उत्पन्न हुआ।

+0

मैं आपको एक संकेत दूंगा - 'ए 'एक रावल नहीं है। – erip

+0

@erip हां, मुझे पता है, लेकिन 'बी' के लिए दो उदाहरणों में क्या अंतर है? – vladon

+0

दूसरे उदाहरण में 'बी' पहले उदाहरण की तरह पहले इसे बढ़ाने के बिना 'ए' का मान प्राप्त करता है। – x13

उत्तर

10

क्योंकि पूर्व वेतन वृद्धि (++a) पहले a का मूल्य वृद्धि कर देता है, परिणाम संग्रहीत करता है, और तोa के संदर्भ देता है। अब a और b प्रभावी ढंग से उसी ऑब्जेक्ट को इंगित करता है।

के बाद वेतन वृद्धि (a++), तथापि, पहला स्टोर एक अस्थायी में a के वर्तमान मूल्य, a वृद्धि कर देता है, और रिटर्न यह अस्थायी - आपके कौन-से rvalue रेफरी अंक। a और b विभिन्न वस्तुओं को इंगित करते हैं, अधिक विशेष रूप से - b बढ़ने से पहले a का अस्थायी होल्डिंग है।

यही वजह है कि यह iterators और अन्य जटिल वस्तुओं है कि वेतन वृद्धि/कमी को परिभाषित करने के लिए it++ से अधिक ++it उपयोग करने के लिए प्रोत्साहित किया जाता है: बाद के अस्थायी प्रतिलिपि बनाता है और इस प्रकार धीमी हो सकती है।

+0

क्या यह यूबी दूसरे उदाहरण में 'ए ++' के बाद 'बी' का उपयोग करने के लिए है? – vladon

+0

और क्यों पहले मामले में कोई अस्थायी नहीं है? क्यों 'auto && b = a ++' 'auto && b = a के बराबर नहीं है; एक ++ '? – vladon

+0

@vladon: मैं _think_ कि अस्थायी तब तक जीवित रहेगा जब तक इसका संदर्भ गुंजाइश से बाहर न हो, जिसका अर्थ है कि यह यूबी नहीं है, लेकिन मुझे यकीन नहीं है। –

1

दूसरे मामले में (बाद में वृद्धि) बी वास्तव में अस्थायी रूप से निर्मित (ए ++) का संदर्भ देता है, इसलिए वृद्धि बी को प्रभावित नहीं करती है।

2

अंतर यह है कि ++a एक अंतराल है, हालांकि a++ नहीं है। यह द्वारा सी ++ 14 [expr.pre.incr]/1 निर्दिष्ट किया जाता है:

उपसर्ग ++ के संकार्य 1 जोड़कर संशोधित किया गया है [...] संकार्य एक परिवर्तनीय lvalue होगा। [...] परिणाम अद्यतन ऑपरेंड है; यह एक lvalue है

और [expr.post.incr]/1:

[...] परिणाम एक prvalue है।


अब हम auto && b = ++a; पर विचार करें। ++a एक लाभा है। auto&& एक अग्रेषण संदर्भ है। फॉरवर्डिंग संदर्भ वास्तव में अंतराल से जुड़ सकते हैं: auto स्वयं संदर्भ प्रकार को घटा सकता है। यह कोड int &b = ++a; पर घटा देता है।

जब कोई संदर्भ उसी प्रकार के अंतराल से बंधे होते हैं, तो संदर्भ सीधे बाध्य होता है, इसलिए ba के लिए एक और नाम बन जाता है।


दूसरे उदाहरण में, auto && b = a++;, a++ एक prvalue है। इसका मतलब है कि इसमें कोई संबंधित पता नहीं है और यह अब a परिवर्तनीय से संबंधित नहीं है। इस पंक्ति में ++a; auto && b = (a + 0); के समान व्यवहार है।

सबसे पहले, a++ एक प्रावधान है, auto&&int&& पर deduces। (यानी autoint को घटा देता है)। जब गैर-वर्ग प्रकार का संदर्भ किसी प्रक्षेपण के लिए बाध्य होता है, तो एक अस्थायी वस्तु मूल्य से प्रति-प्रारंभ की जाती है। संदर्भ के मिलान के लिए इस वस्तु का जीवनकाल बढ़ा है।

तो दूसरे मामले में ba से एक अलग वस्तु के लिए बाध्य है, एक "अस्थायी" पूर्णांक (जो वास्तव में तो अस्थायी नहीं है, क्योंकि यह रूप में लंबे समय b करता है के रूप में रहता है)।

संदर्भ बाध्यकारी नियम [dcl.init.ref] में हैं।

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