2017-12-05 30 views
9

क्या नियुक्ति के वापसी मूल्य और उसके ऑपरेंड के जाली मूल्य के बीच कोई (अर्थपूर्ण) अंतर है?क्या नियुक्ति के वापसी मूल्य और उसके ऑपरेंड के जाली मूल्य के बीच कोई (अर्थपूर्ण) अंतर है?

struct Foo { ... }; 
char buffer[...]; 

Foo *a = new(buffer) Foo; 
Foo *b = reinterpret_cast<Foo *>(buffer); 

करता a और b किसी तरह भिन्न हैं?


संपादित करें: DaBler की टिप्पणी के आधार पर, इस सवाल का बताता है एक अंतर है, वहाँ यह है कि अगर स्थिरांक/संदर्भ सदस्यों का प्रयोग किया: Placement new and assignment of class with const member

तो, मेरी छोटी-बिट अद्यतन प्रश्न: क्या a और b में मतभेद किसी भी तरह, अगर Foo में कोई आधार या संदर्भ सदस्य नहीं है?

+1

नई (बफर) फू; वस्तु के निर्माता को बुलाएगा; दूसरा नहीं है। – UKMonkey

+1

@UKMonkey: क्षमा करें, शायद मैं पर्याप्त स्पष्ट नहीं था। दोनों लाइनें चलती हैं, पहले प्लेसमेंट नई, और फिर कास्ट। – geza

+0

हां, कक्षा में कॉन्स सदस्य होने पर कोई अंतर होता है। विवरण के लिए [यह प्रश्न] देखें (https://stackoverflow.com/questions/47473621/placement-new-and-assignment-of-class-with-const-member)। – DaBler

उत्तर

2

a के माध्यम से प्रवेश कानूनी है जबकि b नहीं है। [basic.compound] से

दो वस्तुओं a और b हैं सूचक-बदलने के योग्य हैं:

  • वे एक ही वस्तु है, या

  • एक एक मानक लेआउट संघ वस्तु है और अन्य है उस ऑब्जेक्ट का एक गैर स्थैतिक डेटा सदस्य, या

  • एक मानक-लेआउट क्लास ऑब्जेक्ट है और दूसरा है उस ऑब्जेक्ट का पहला गैर स्थैतिक डेटा सदस्य, या, यदि ऑब्जेक्ट में कोई गैर-स्थैतिक डेटा सदस्य नहीं है, तो उस ऑब्जेक्ट का पहला बेस क्लास सबोबजेक्ट ([class.mem]), या

  • कोई ऑब्जेक्ट मौजूद है c जैसे a और c पॉइंटर-इंटरकॉन्टेबलबल हैं, और c और b पॉइंटर-इंटरकॉन्टेबल हैं।

दो वस्तुओं सूचक-बदलने के योग्य हैं, तो वे एक ही पता है, और यह एक reinterpret_­cast के माध्यम से दूसरे के लिए एक सूचक से एक के लिए एक सूचक प्राप्त करने के लिए संभव है। [नोट: एक सरणी ऑब्जेक्ट और उसका पहला तत्व पॉइंटर-इंटरकॉन्टेबल नहीं है, भले ही उनके पास एक ही पता हो। - अंत नोट]

वे एक ही वस्तु नहीं हैं, यूनियन नहीं हैं और एक दूसरे के अधीन नहीं हैं, इसलिए पॉइंटर-इंटरकॉन्टीबल नहीं।

नोट [expr.reinterpret.cast] केवल reinterpret_cast<char*>(b) == buffer की गारंटी देता है।

एक ऑब्जेक्ट पॉइंटर को एक अलग प्रकार के ऑब्जेक्ट पॉइंटर में स्पष्ट रूप से परिवर्तित किया जा सकता है। जब ऑब्जेक्ट पॉइंटर प्रकार का v ऑब्जेक्ट पॉइंटर प्रकार "पॉइंटर से cv T" में परिवर्तित किया जाता है, तो परिणाम static_­cast<cv T*>(static_­cast<cv void*>(v)) होता है। [नोट: अपने मूल प्रकार (जहां T1 और T2 वस्तु प्रकार के होते हैं और जहां T2 के संरेखण आवश्यकताओं कोई T1 की से अधिक सख्त कर रहे हैं) "T2 सूचक" "T1 सूचक" प्रकार का एक prvalue परिवर्तित प्रकार के और वापस मूल सूचक मूल्य उत्पन्न करता है।- अंत टिप्पणी]

6

केवल a सुरक्षित रूप से सीधे नियुक्ति नई अभिव्यक्ति (जिसे हम संदर्भ में आसानी के लिए x फोन करता हूँ) द्वारा बनाई गई Foo वस्तु का उपयोग करने के लिए इस्तेमाल किया जा सकता है। b का उपयोग std::launder की आवश्यकता है।

a का मूल्य [expr.new]/1 में निर्दिष्ट किया जाता: इकाई एक गैर सरणी वस्तु, नई अभिव्यक्ति का परिणाम है

तो निर्मित ऑब्जेक्ट के लिए सूचक है।

a का मान इसलिए "x पर सूचक" है। यह पॉइंटर, निश्चित रूप से x तक पहुंचने के लिए सुरक्षित रूप से उपयोग किया जा सकता है।

reinterpret_cast<Foo*>(buffer)buffer पर सरणी-से-पॉइंटर रूपांतरण लागू करता है ([expr.reinterpret.cast]/1 देखें)। रूपांतरण के बाद परिणामी मूल्य लागू होता है "buffer के पहले तत्व के सूचक"। यह एक ऑब्जेक्ट पॉइंटर का एक reinterpret_cast है जो किसी ऑब्जेक्ट पॉइंटर को किसी भिन्न प्रकार के ऑब्जेक्ट पॉइंटर पर है, और static_cast<Foo*>(static_cast<void*>(buffer)) के बराबर [expr.reinterpret.cast]/7 के रूप में परिभाषित किया गया है।

आंतरिक कास्ट void* वास्तव में एक निहित रूपांतरण है। प्रति [conv.ptr]/2,

पॉइंटर मान इस रूपांतरण से अपरिवर्तित है।

इसलिए भीतरी डाली मूल्य "buffer के पहले तत्व के लिए सूचक" के साथ एक void* अर्जित करता है।

प्रकार का एक prvalue "सूचक को CV1void" प्रकार का एक prvalue में बदला जा सकता "सूचक:

बाहरी कलाकारों [expr.static.cast]/13, जो मैं हल्के से बुलेट बिंदुओं में पुन: स्वरूपित किया द्वारा नियंत्रित होता है CV2T ", जहाँ T एक वस्तु प्रकार और CV2 है के रूप में एक ही सीवी-योग्यता, या अधिक से अधिक सीवी-योग्यता, CV1 है।

  • मूल सूचक मूल्य स्मृति में एक बाइट का पता A का प्रतिनिधित्व करता है और AT के संरेखण आवश्यकता को पूरा नहीं करता है, फिर परिणामी सूचक मूल्य अनिर्दिष्ट है।

  • अन्यथा, यदि एक वस्तु a, और वहाँ एक वस्तु प्रकार T की b है करने के लिए मूल सूचक मूल्य अंक (अनदेखी सीवी-योग्यता) कि सूचक-बदलने के योग्य a साथ है, परिणाम b के लिए सूचक है ।

  • अन्यथा, सूचक मूल्य रूपांतरण द्वारा अपरिवर्तित है।

यह मानते हुए कि buffer उपयुक्त रूप से गठबंधन किया है (आप मुसीबत में अच्छी तरह से इस बिंदु से पहले अगर यह नहीं है हो जाएगा), पहले बुलेट लागू नहीं है। दूसरा बुलेट इसी तरह अपरिहार्य है क्योंकि यहां कोई pointer-interconvertiblity नहीं है। यह इस प्रकार है कि हमने तीसरी गोली मार दी - "सूचक मूल्य रूपांतरण द्वारा अपरिवर्तित है" और "buffer के पहले तत्व के सूचक" बना हुआ है।

इस प्रकार, bFoo ऑब्जेक्ट x पर इंगित नहीं करता है; यह buffer के पहले char तत्व के बजाय इंगित करता है, भले ही इसका प्रकार Foo* है। इसलिए इसका उपयोग x तक पहुंचने के लिए नहीं किया जा सकता है; ऐसा करने का प्रयास अपरिभाषित व्यवहार पैदा करता है (गैर-स्थैतिक डेटा सदस्य मामले के लिए, [expr.ref] से चूककर; गैर-स्थिर सदस्य फ़ंक्शन केस के लिए, [class.mfct.non-static]/2 द्वारा)।

b से x के लिए सूचक को ठीक करने के लिए, std::launder इस्तेमाल किया जा सकता:

b = std::launder(b); // value of b is now "pointer to x" 
        // and can be used to access x 
संबंधित मुद्दे