2012-07-02 28 views
15

यह प्रश्न here टिप्पणियों से प्रेरित है।क्या मानक-अनुपालन संकलक गैर-पॉलिमॉर्फिक प्रकार से डायनामिक_कास्ट डाउनकास्ट युक्त कोड को अस्वीकार कर सकता है?

पर विचार करें निम्नलिखित कोड का टुकड़ा:

struct X {}; // no virtual members 
struct Y : X {}; // may or may not have virtual members, doesn't matter 

Y* func(X* x) { return dynamic_cast<Y*>(x); } 

कई लोगों ने सुझाव दिया है कि उनके संकलक func के शरीर अस्वीकार होगा।

हालांकि, मुझे लगता है कि मानक द्वारा परिभाषित किया गया है कि x के रन-टाइम मान पर निर्भर करता है। खंड 5.2.7 ([expr.dynamic.cast]) से:

  1. अभिव्यक्ति dynamic_cast<T>(v) का परिणाम अभिव्यक्ति v परिवर्तित टाइप करने के लिए T का परिणाम है। T एक पूर्ण श्रेणी प्रकार के संदर्भ में एक सूचक या होगा, या "सीवीvoid पर सूचक।" dynamic_cast ऑपरेटर स्थिरता को दूर नहीं करेगा।

  2. तो T एक सूचक प्रकार है, v पूरा करने के लिए वर्ग प्रकार एक सूचक की एक prvalue होगा, और परिणाम प्रकार T के prvalue है। यदि T एक लाभा संदर्भ प्रकार है, v एक पूर्ण श्रेणी प्रकार का एक आभासी होगा, और परिणाम T द्वारा निर्दिष्ट प्रकार का एक अंतराल है। यदि T एक रैवल्यू संदर्भ प्रकार है, v एक पूर्ण वर्ग प्रकार, वाला एक अभिव्यक्ति होगा और परिणाम T द्वारा निर्दिष्ट प्रकार का एक xvalue होगा।

  3. तो v की प्रकार T रूप में ही है, या यह एक ही है के रूप में T सिवाय इसके कि T में वर्ग ऑब्जेक्ट प्रकार v में वर्ग ऑब्जेक्ट प्रकार की तुलना में अधिक सीवी-योग्य है, परिणाम है v (यदि आवश्यक हो तो परिवर्तित)।

  4. तो v का मूल्य सूचक मामले में एक नल पॉइंटर मूल्य है, परिणाम प्रकार T के नल पॉइंटर मूल्य है।

  5. तो टी है "सूचक को CV1B" और v 'सूचक CV2D करने के लिए "ऐसी है कि BD का एक आधार वर्ग है टाइप किया है, परिणाम अद्वितीय B करने के लिए एक सूचक है D ऑब्जेक्ट का उपरोक्त v द्वारा इंगित किया गया। इसी तरह, अगर टी और v "CV1B के संदर्भ में" है परिणाम D वस्तु v से संबोधित किया जाता का अनूठा B subobject है टाइप CV2D ऐसी है कि BD का एक आधार वर्ग है,। नतीजा यह है कि T एक लाभा संदर्भ है, या T एक रावल्यू संदर्भ है, तो एक अंडाकार है। दोनों सूचक और संदर्भ मामलों में, कार्यक्रम बीमार बनाई है अगर CV2CV1 से अधिक से अधिक सीवी-योग्यता है या B एक दुर्गम या D की अस्पष्ट आधार वर्ग है यदि।

  6. अन्यथा, v एक पॉइंटरॉर्फिक प्रकार के पॉइंटर या एक लाइव्यू होगा।

  7. तो T है "सूचक सीवीvoid लिए," तो परिणाम सबसे व्युत्पन्न वस्तु के लिए एक सूचक v द्वारा की ओर इशारा किया है। अन्यथा, एक रन-टाइम जांच को देखने के लिए अन्य शामिल कर सकते हैं प्रकार उठाई या T द्वारा कहा जाता है।) में बदला जा सकता लागू किया जाता है, तो वस्तु बताया या करने के लिए भेजा v द्वारा सबसे व्युत्पन्न वस्तु बताया या करने के लिए भेजा v द्वारा B बेस क्लास के रूप में ऑब्जेक्ट्स, लेकिन इन्हें अनदेखा किया जाता है।

  8. हैं C वर्ग प्रकार है जो करने के लिए T अंक या संदर्भित करता है, रन-टाइम जांच तार्किक कार्यान्वित इस प्रकार है:

    • हैं, तो सबसे व्युत्पन्न वस्तु बताया (कहा जाता है) में से करने के लिए v, v अंक (संदर्भित करता है) एक C वस्तु का एक public आधार वर्ग subobject के लिए, और प्रकार C का केवल एक ही वस्तु ०१२३९९२७८९७३ द्वारा करने के लिए subobject बताया (कहा जाता है) से ली गई है, तो परिणाम अंक (संदर्भ) उस C ऑब्जेक्ट पर।

    • अन्यथा, यदि v अंक (संदर्भित करता है) सबसे व्युत्पन्न वस्तु, और सबसे व्युत्पन्न वस्तु के प्रकार की एक public आधार वर्ग subobject करने के लिए एक आधार वर्ग, प्रकार C की, कि स्पष्ट है और public है , परिणाम बिंदु (संदर्भ) C सबसे व्युत्पन्न वस्तु का सबोबजेक्ट।

    • अन्यथा, रन-टाइम चेक विफल रहता है।

  9. सूचक प्रकार के एक असफल कलाकारों के मूल्य अपेक्षित परिणाम प्रकार की अशक्त सूचक मान है। संदर्भ std::bad_cast को संदर्भित करने में असफल कलाकार।

तरह से मैं यह पढ़, एक बहुरूपी प्रकार की आवश्यकता को ही लागू होता है अगर उपरोक्त शर्तों में से कोई भी मुलाकात कर रहे हैं, और उन शर्तों में से एक क्रम मूल्य पर निर्भर करता है।

बेशक, कुछ मामलों में संकलक सकारात्मक रूप से निर्धारित कर सकता है कि इनपुट ठीक से नहीं हो सकता है (उदाहरण के लिए, जब यह this पॉइंटर है), लेकिन मुझे अभी भी लगता है कि संकलक कोड को अस्वीकार नहीं कर सकता है जब तक कि यह निर्धारित नहीं हो जाता कथन पूरा हो जाएगा (आमतौर पर एक रन-टाइम प्रश्न)।

एक चेतावनी निदान यहां निश्चित रूप से मूल्यवान है, लेकिन क्या यह संकलक के लिए इस कोड को अस्वीकार करने के लिए मानक-अनुरूप है?

+1

6. बहुत अधिक क्रिस्टल स्पष्ट है, है ना? विशेष रूप से उपरोक्त सब कुछ लागू नहीं होता है। –

+2

@AlexandreC .: दिखाए गए कोड से आप कैसे बता सकते हैं, कि (4) लागू नहीं होता है? ध्यान दें कि यह "शून्य सूचक * मान *" कहता है, जो रनटाइम तक ज्ञात नहीं हो सकता है, न कि "शून्य सूचक * शाब्दिक *" या "शून्य सूचक * स्थिर *"। –

+0

(मैं डाउनवॉटर नहीं हूं)। दरअसल, मैंने इन पंक्तियों के साथ "शून्य सूचक 'शाब्दिक' या कुछ पढ़ा। क्या आप यह इंगित करने की कोशिश कर रहे हैं कि संकलक को डायनामिक कास्ट को 'assert (! V)' या गैर पॉलिमॉर्फिक मामले में समान कुछ में अनुवाद करना चाहिए? –

उत्तर

3

एक बहुत अच्छा बिंदु।

ध्यान दें कि सी ++ 03 में 5.2.7/3 और 5.2.7/4 के शब्द के रूप में

का अनुसरण करती है वी के प्रकार के लिए आवश्यक रूप में ही है परिणाम प्रकार (जो, सुविधा के लिए, इस विवरण में आर कहा जाएगा), या इसे आर सिवाय इसके कि आर में वर्ग ऑब्जेक्ट प्रकार अधिक सीवी योग्य वर्ग वस्तु से है ही के रूप में है में टाइप करें v, परिणाम v (यदि आवश्यक हो तो परिवर्तित)।

तो वी का मूल्य सूचक मामले में एक नल पॉइंटर मूल्य है, परिणाम प्रकार आर के नल पॉइंटर मूल्य है।

संदर्भ टाइप करने के लिए R में 5.2.7/3 सूचित करते हैं कि 5.2.7/4 5.2.7/3 की उप-धारा में किया जाता है लगता है की शुरुआत की। दूसरे शब्दों में, ऐसा लगता है कि 5.2.7/4 केवल 5.2.7/3 में वर्णित शर्तों के तहत लागू करने का इरादा है, यानी जब प्रकार समान होते हैं।

हालांकि, सी ++ 11 में शब्द अलग है और अब R शामिल नहीं है, जो अब 5.2.7/3 और 5.2.7/4 के बीच किसी विशेष संबंध का सुझाव नहीं देता है। मुझे आश्चर्य है कि यह जानबूझकर बदल गया है ...

+0

यह देखते हुए कि सभी संकलक जिनके पास सी ++ 0x/11 मोड में सी ++ 98/03 मोड में समान त्रुटि देने के लिए पहुंच है, और उनमें से अधिकतर समिति में शामिल लोगों को शामिल करते हैं, मुझे संदेह है कि यह नहीं था जानबूझकर बदल नहीं है। – abarnert

+0

व्याख्या (4) के उप-खंड (3) के रूप में कोई समझ नहीं आता है। (3) पहले से ही कहा गया है कि परिणाम क्या है, यह 'v' है। (3) की आवश्यकताओं को पूरा करने पर, शून्य सूचक मानों के बारे में थोड़ा सा जोड़ना 100% अनावश्यक है। फिर भी, यह 'आर' की उपस्थिति के बारे में एक बहुत अच्छा अवलोकन है। –

+0

@abarnert: हाँ, लेकिन अब सी ++ 11 में उपयोग की जाने वाली शब्द ओपी में बताए गए कारणों के लिए भ्रमित है। 5.2.7 को "सीढ़ियों की स्थिति" संरचना का पालन करना है, लेकिन संभावित रूप से यह मानता है कि शून्य पॉइंटर्स को बिना शर्त अनुमति दी जानी चाहिए। – AnT

3

मेरा मानना ​​है कि उस शब्द का इरादा यह है कि कुछ जानवरों को संकलन समय पर किया जा सकता है, उदाहरण के लिए अपस्टास्ट या dynamic_cast<Y*>((X*)0), लेकिन दूसरों को रन-टाइम चेक की आवश्यकता होती है (जिस स्थिति में एक पॉलिमॉर्फिक प्रकार की आवश्यकता होती है।)

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

DR 665 देखें जो स्पष्ट करता है कि कुछ जानवरों को रन-टाइम पर स्थगित करने के बजाए संकलन-समय पर खराब गठित किया गया है।

+0

मुझे नहीं लगता कि एक नल-पॉइंटर निरंतर 'गतिशील_कास्ट' के लिए एक तर्क का उपयोग किया जा सकता है। 'dynamic_cast' शून्य-पॉइंटर मान की अनुमति देता है, लेकिन एक नल-पॉइंटर निरंतर को बिना किसी कलाकार के शून्य-सूचक मूल्य में परिवर्तित किया जा सकता है। – AnT

+0

उदाहरण को ठीक करने के लिए संपादित किया गया है, और अंतिम अनुच्छेद को हटा दें कि मुझे DR 665 के संदर्भ के लिए –

+0

+1 का कम यकीन है। – abarnert

1

मेरे लिए, यह बहुत स्पष्ट कट लगता है। मुझे लगता है कि भ्रम आता है जब आप गलत व्याख्या करते हैं कि आवश्यकताओं की गणना एक और है यदि अन्य .. .. अगर .. .. "चीज का प्रकार।

अंक (1) और (2) सीवी-योग्यता और lvalue-rvalue-prvalue-- आदि के संदर्भ में स्थिर इनपुट और आउटपुट प्रकारों को बस परिभाषित करने की अनुमति है, तो यह मामूली है और सभी मामलों पर लागू होता है ।

प्वाइंट (3) बहुत स्पष्ट है, यदि इनपुट और आउटपुट प्रकार दोनों समान हैं (सीवी-क्वालीफायर अलग-अलग जोड़े गए हैं), तो रूपांतरण छोटा है (कोई भी नहीं, या केवल सीवी-क्वालीफायर जोड़ा गया है)।

प्वाइंट (4) स्पष्ट रूप से आवश्यक है कि यदि इनपुट पॉइंटर शून्य है, तो आउटपुट पॉइंटर भी शून्य है। इस बिंदु को एक आवश्यकता के रूप में बनाया जाना चाहिए, न कि कास्ट को अस्वीकार करने या स्वीकार करने के मामले में (स्थैतिक विश्लेषण के माध्यम से), लेकिन इस तथ्य पर जोर देने के मामले में कि यदि इनपुट पॉइंटर से आउटपुट पॉइंटर में रूपांतरण सामान्य रूप से ऑफ़सेट हो जाता है वास्तविक सूचक मूल्य (जैसा कि यह एकाधिक विरासत वर्ग पदानुक्रमों के तहत हो सकता है), तो पॉइंटर की "शून्यता" को संरक्षित करने के लिए इनपुट पॉइंटर शून्य होने पर ऑफ़सेट लागू नहीं किया जाना चाहिए। इसका मतलब यह है कि जब गतिशील-कास्ट किया जाता है, तो पॉइंटर को शून्यता के लिए चेक किया जाता है, और यदि यह शून्य है, परिणामी पॉइंटर के पास शून्य-मूल्य होना चाहिए।

प्वाइंट (5) बस कहता है कि यदि यह एक उथल-पुथल (बेस से व्युत्पन्न) है, तो कास्ट स्थिर रूप से हल हो जाती है (static_cast<T>(v) के बराबर)। यह ज्यादातर मामले को संभालने के लिए होता है (जैसा कि फुटनोट इंगित करता है) जहां उथल-पुथल अच्छी तरह से गठित होता है, लेकिन अगर किसी व्यक्ति द्वारा सबसे अधिक व्युत्पन्न वस्तु पर जाना होता है तो बीमार गठित कलाकार की संभावना हो सकती है (उदाहरण के लिए, यदि वी मूल बिंदु कई मूल वर्गों के साथ व्युत्पन्न वस्तु को इंगित करता है जिसमें कक्षा टी एक से अधिक बार प्रकट होता है)। दूसरे शब्दों में, इसका मतलब है, यदि यह एक उथल-पुथल है, तो इसे स्थिर समय पर चलाएं, बिना रन-टाइम तंत्र (इस प्रकार, संभावित विफलता से परहेज करें, जहां यह नहीं होना चाहिए)। इस मामले के तहत, संकलक को उसी आधार पर कास्ट को अस्वीकार कर देना चाहिए जैसे कि यह static_cast<T>(v) था।

प्वाइंट (6) में, स्पष्ट रूप से, "अन्यथा" सीधे प्वाइंट (5) (और निश्चित रूप से प्वाइंट (3) के मामूली मामले को संदर्भित करता है)। मतलब (प्वाइंट (7) के साथ), कि अगर कास्ट एक उग्र नहीं है (और पहचान-कास्ट नहीं है (प्वाइंट (3)), तो यह एक डाउन-कास्ट है, और इसे रन-टाइम पर हल किया जाना चाहिए , स्पष्ट आवश्यकता के साथ कि प्रकार (v) एक पॉलिमॉर्फिक प्रकार (वर्चुअल फ़ंक्शन है) हो।

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

बेशक, वे एक अलग विकल्प बना सकते थे, और आधार को आधार से व्युत्पन्न (यानी, बिना रन-टाइम चेक के) के रूप में व्यवहार करने के लिए अनुमति दी जाती है, जब मूल प्रकार पॉलिमॉर्फिक नहीं होता है, लेकिन मुझे लगता है कि गतिशील-कास्ट के अर्थशास्त्र को तोड़ता है, जो स्पष्ट रूप से कहता है "मैं इस कलाकार पर रन-टाइम जांच चाहता हूं", अन्यथा आप एक गतिशील-कास्ट का उपयोग नहीं करेंगे!

+0

यह पहले से ही सुझाव दिया गया है, लेकिन "अन्यथा" को बिंदु 3 शामिल करना है। यहां तक ​​कि आपकी स्पष्टीकरण मानता है कि यह करता है। इसके अलावा, मानक में कई जगहें हैं जहां व्याख्या "अन्य अगर ... और अगर ... और" बिल्कुल सही है। और मामले (5) से संबंधित आपका अंतिम वाक्य गलत है, संकलक 'static_cast (x)' को अस्वीकार नहीं करेगा। –

+0

@ बेन वोगेट: मेरा मतलब था (बिंदु (5) में) कि इसे स्थिर-कास्ट के समान मानदंडों के आधार पर कलाकार की वैधता का न्याय करना चाहिए, मेरा मतलब यह नहीं था कि आपका विशेष उदाहरण अस्वीकार कर दिया जाना चाहिए। –

+0

आह ठीक है, उस हिस्से को समझने पर वह हिस्सा समझ में आता है। लेकिन "अन्यथा" के रूप में "अन्य 5" के रूप में व्यवहार करना अभी भी विफल रहता है, क्योंकि यह 3. –