दिलचस्प पोस्ट
संदर्भ कॉल द्वारा std :: थ्रेड पास प्रतिलिपि कन्स्ट्रक्टर जेनेरिक में सी # का इस्तेमाल करते हुए मठ पुस्तकालय का निर्माण कैसे जावा के साथ SQLite कनेक्ट करने के लिए? cout या printf दोनों में से कौन सी गतिशील निष्पादन गति C ++ है? कैसे 64-बिट विंडो में प्रवेश डेटाबेस के साथ आर कनेक्ट करने के लिए? स्प्रिंग बूट और एनोटेशन के साथ ViewResolver को कॉन्फ़िगर करें, URI त्रुटि के साथ HTTP अनुरोध के लिए कोई मानचित्रण नहीं मिला स्ट्रिंग में एक गणितीय अभिव्यक्ति का मूल्यांकन करना किसी तत्व का चयन करें जब क्लास का नाम एक निश्चित शब्द से शुरू होता है जावा में regex को समझना: विभाजित ("\ t") बनाम विभाजन ("\\ t") – वे दोनों काम करते हैं, और उन्हें कब उपयोग किया जाना चाहिए एंड्रॉइड ऐप से वाईफाई नेटवर्क से जुड़ी सभी डिवाइसों का पता कैसे लगाया जाता है Matplotlib लाइन के साथ scatterplot अंक कनेक्ट – अजगर सीडीआई और ईजेबी कैसे तुलना करते हैं? बातचीत? एम एक्स एन टेबल के रूप में एक नोड अनुक्रम प्रदान करना LINQ की विशिष्ट () के लिए समानता की तुलना के लिए एक प्रतिनिधि का उपयोग करें एंड्रॉइड: टाइमर धागा से यूआई एलीमेंट एक्सेस करना

`एल *` के साथ `टी *` का एलिसिशन अनुमति है। क्या यह दूसरी तरह के आसपास की अनुमति है?

नोट: इसे और अधिक केंद्रित और पठनीय बनाने के लिए इस प्रश्न का नाम बदल दिया गया है और कम कर दिया गया है। अधिकांश टिप्पणियां पुरानी पाठ को दर्शाती हैं

मानक के अनुसार, विभिन्न प्रकार के ऑब्जेक्ट समान स्मृति स्थान साझा नहीं कर सकते हैं। तो यह कानूनी नहीं होगा:

std::array<short, 4> shorts; int* i = reinterpret_cast<int*>(shorts.data()); // Not OK 

मानक, हालांकि, इस नियम को अपवाद की अनुमति देता है: किसी ऑब्जेक्ट को पॉइंटर के माध्यम से char या unsigned char तक पहुंचा जा सकता है:

 int i = 0; char * c = reinterpret_cast<char*>(&i); // OK 

हालांकि, मुझे यह स्पष्ट नहीं है कि क्या यह अन्य तरह के आसपास की अनुमति भी है। उदाहरण के लिए:

 char * c = read_socket(...); unsigned * u = reinterpret_cast<unsigned*>(c); // huh? 

Solutions Collecting From Web of "`एल *` के साथ `टी *` का एलिसिशन अनुमति है। क्या यह दूसरी तरह के आसपास की अनुमति है?"

शामिल कुछ पॉइंटर रूपांतरणों के कारण आपका कुछ कोड संदिग्ध है। ध्यान रखें कि उन उदाहरणों में reinterpret_cast<T*>(e) में static_cast<T*>(static_cast<void*>(e)) का अर्थ है क्योंकि इसमें शामिल प्रकार मानक-लेआउट हैं। (मैं वास्तव में यह सुझाव देता हूं कि आप हमेशा static_cast cv void* माध्यम से static_cast इस्तेमाल करते हैं जब स्टोरेज से निपटते हैं।)

स्टैंडर्ड का एक करीबी पठन यह सुझाव देता है कि T* पर या से एक सूचक रूपांतरण के दौरान यह माना जाता है कि वास्तव में एक वास्तविक वस्तु है T* शामिल है – जो आपके कुछ स्निपेट में पूरा करना कठिन है, भले ही 'धोखाधड़ी' का धन्यवाद शामिल प्रकार की तुच्छता (बाद में इस पर अधिक) यह बिंदु के अलावा होगा, क्योंकि …

पदानकर्ता रूपांतरण के बारे में एलियाज़िंग नहीं है यह सी ++ 11 टेक्स्ट है जो नियमों को रूपरेखा करता है जिन्हें सामान्यतः 'सख्त अलियासिंग' नियमों के रूप में संदर्भित किया जाता है, 3.10 लावल्यूज़ और रैवल्यूज़ से [basic.lval]:

10 यदि कोई प्रोग्राम किसी ऑब्जेक्ट के संग्रहीत मूल्य को निम्नलिखित प्रकारों में से एक के अलावा अन्य के ग्लोबल तक पहुंचने का प्रयास करता है तो व्यवहार अनिर्धारित है:

  • वस्तु का गतिशील प्रकार,
  • ऑब्जेक्ट के डायनामिक प्रकार का एक सीवी-योग्य संस्करण,
  • ऑब्जेक्ट के डायनेमिक प्रकार को एक प्रकार समान (जैसा कि 4.4 में परिभाषित किया गया है)
  • एक प्रकार जो ऑब्जेक्ट के डायनेमिक प्रकार से संबंधित एक हस्ताक्षरित या अहस्ताक्षरित प्रकार है,
  • एक प्रकार जो हस्ताक्षरित या अहस्ताक्षरित प्रकार वस्तु के गतिशील प्रकार के सीवी-योग्य संस्करण के अनुरूप होता है,
  • एक समग्र या यूनियन प्रकार जिसमें इसके तत्वों या गैर-स्थिर डेटा सदस्यों में से एक शामिल होता है (जिसमें एक पुनरावर्ती, एक तत्व या गैर-स्थैतिक डेटा सदस्य का एक सबगैगेट या संघ शामिल है),
  • ऑब्जेक्ट के डायनामिक प्रकार के एक प्रकार (संभवतः सीवी-योग्य) बेस क्लास प्रकार है,
  • एक चार या अहस्ताक्षरित चार प्रकार

(यह सी ++ 03 में एक ही खंड और उप-खंड के पैराग्राफ 15 है, उदाहरण के साथ 'glvalue' के बजाय 'lvalue' का उपयोग किया जाने वाला पाठ में कुछ मामूली बदलाव के साथ, बाद में एक सी ++ 11 धारणा है।)

उन नियमों के प्रकाश में, मान लें कि एक कार्यान्वयन हमें magic_cast<T*>(p) साथ प्रदान करता है, जो कि 'किसी तरह' एक सूचक को अन्य सूचक प्रकार में परिवर्तित करता है। आम तौर पर यह reinterpret_cast होगा , जो कुछ मामलों में अनिर्दिष्ट परिणाम देता है, लेकिन जैसा कि मैंने समझाया है इससे पहले कि यह मानक-लेआउट प्रकारों के संकेत के लिए नहीं है। तो यह स्पष्ट रूप से सच है कि आपके सभी स्निपेट्स सही हैं ( magic_cast साथ reinterpret_cast magic_cast ), क्योंकि मैजिक_कास्ट के परिणामों के साथ कोई ग्लॉल्यूज़ शामिल नहीं है।

यहां एक स्निपेट है जो गलत तरीके से magic_cast उपयोग magic_cast , लेकिन जिसे मैं तर्क देता हूं वह सही है:

 // assume constexpr max constexpr auto alignment = max(alignof(int), alignof(short)); alignas(alignment) char c[sizeof(int)]; // I'm assuming here that the OP really meant to use &c and not c // this is, however, inconsequential auto p = magic_cast<int*>(&c); *p = 42; *magic_cast<short*>(p) = 42; 

मेरी तर्क को औचित्यपूर्ण करने के लिए, यह अनियमित रूप से अलग स्निपेट मानें:

 // alignment same as before alignas(alignment) char c[sizeof(int)]; auto p = magic_cast<int*>(&c); // end lifetime of c c.~decltype(c)(); // reuse storage to construct new int object new (&c) int; *p = 42; auto q = magic_cast<short*>(p); // end lifetime of int object p->~decltype(0)(); // reuse storage again new (p) short; *q = 42; 

यह स्निपेट का ध्यानपूर्वक निर्माण किया गया है। विशेष रूप से, new (&c) int; मुझे उपयोग &c की अनुमति है, भले ही c को 3.8 ऑब्जेक्ट आजीवन [बुनियादी। जीवन] के पैरा 5 में दिए गए नियमों के कारण नष्ट हो गया। उसी के अनुच्छेद 6 में भंडारण के संदर्भ में बहुत ही नियम दिए गए हैं और पैराग्राफ 7 बताता है कि एक बार स्टोरेज का पुन: उपयोग करने के बाद एक वस्तु को संदर्भित करने वाले वेरिएबल्स, पॉइंटर्स और संदर्भों का क्या होता है – मैं उनको सामूहिक रूप से 3.8 / 5- 7।

इस उदाहरण में &c (अस्पष्ट रूप से) को void* परिवर्तित किया जाता void* , जो स्टोरेज के एक सूचक के सही उपयोग में से एक है जिसे अभी तक पुन: उपयोग नहीं किया गया है। इसी तरह p ए से प्राप्त किया जाता है &c इससे पहले कि नए int का निर्माण किया जाता है। इसकी परिभाषा शायद c के विनाश के बाद ले जाई जा सकती है, इस पर निर्भर करता है कि कार्यान्वयन के जादू कितना गहरा है, लेकिन निश्चित रूप से int निर्माण के बाद नहीं: पैरा 7 लागू होगा और यह अनुमत स्थितियों में से एक नहीं है short वस्तु का निर्माण भी p पर निर्भर करता है जो भंडारण के लिए एक संकेतक बनता है।

अब, क्योंकि int और short तुच्छ प्रकार हैं, मुझे डिस्ट्रक्टर्स के लिए स्पष्ट कॉल का उपयोग नहीं करना पड़ता है। मुझे कंसल्टेंट्स को स्पष्ट कॉल की ज़रूरत नहीं है, या तो (यह कहने के लिए, सामान्य रूप से कॉल, स्टैंडर्ड प्लेसमेंट नई <new> में घोषित) 3.8 ऑब्जेक्ट जीवनकाल से [basic.life]:

1 […] प्रकार टी के एक उद्देश्य के जीवनकाल शुरू होता है जब:

  • प्रकार टी के लिए उचित संरेखण और आकार के साथ भंडारण प्राप्त किया जाता है, और
  • यदि ऑब्जेक्ट में नॉन-तुच्छ इनिशियलाइज़ेशन है, तो इसका इनिशियलाइज़ेशन पूरा हो गया है।

टाइप टी के ऑब्जेक्ट का जीवनकाल समाप्त होता है जब:

  • यदि टी एक गैर-क्षुद्र नाशक (12.4) के साथ एक वर्ग प्रकार है, तो नाशक कॉल शुरू होता है, या
  • भंडारण जो ऑब्जेक्ट के कब्जे में आता है या फिर पुन: उपयोग किया जाता है।

इसका मतलब है कि मैं इस कोड को फिर से लिख सकता हूं कि, मध्यवर्ती चर q तहने के बाद, मैं मूल स्निपेट के साथ समाप्त होता हूं।

ध्यान दें कि p को दूर नहीं किया जा सकता है इसका अर्थ यह है कि निम्नलिखित परिभाषित गलत है:

 alignas(alignment) char c[sizeof(int)]; *magic_cast<int*>(&c) = 42; *magic_cast<short*>(&c) = 42; 

यदि हम यह मानते हैं कि दूसरी वस्तु के साथ एक int वस्तु (त्रिकोणीय) का निर्माण किया गया है, तो इसका मतलब यह है कि &c उपयोग पुन: उपयोग किया गया भंडारण के लिए एक सूचक हो जाता है। इस प्रकार तीसरी पंक्ति गलत है – हालांकि 3.8 / 5-7 की वजह से और नियमों को अलविदा करते हुए कड़ाई से बोलने के कारण नहीं।

अगर हम यह नहीं मानते हैं, तो दूसरी पंक्ति में अलियासिंग नियमों का उल्लंघन है: हम पढ़ रहे हैं वास्तव में एक char c[sizeof(int)] प्रकार की एक प्रकार के ग्लेव्यू के माध्यम से वस्तु है, जो कि अनुमत नहीं है अपवाद। तुलना करके, *magic_cast<unsigned char>(&c) = 42; ठीक हो जाएगा (हम तीसरी पंक्ति पर एक short वस्तु कमजोर कर रहे हैं)।

अल्फ की तरह, मैं यह भी अनुशंसा करता हूं कि भंडारण का उपयोग करते समय आप स्पष्ट रूप से मानक प्लेसमेंट का उपयोग करते हैं। तुच्छ प्रकारों के लिए विनाश को *some_magic_pointer = foo; ठीक है, लेकिन कुछ *some_magic_pointer = foo; आप 3.8 / 5-7 के उल्लंघन का सामना कर रहे हैं (कोई बात नहीं कैसे संकेत मिलता है कि पॉईंटर कैसे प्राप्त किया गया था) या अलियासिंग नियमों का इसका अर्थ है नई अभिव्यक्ति का परिणाम संचय करना, क्योंकि जब आपका ऑब्जेक्ट तैयार हो जाने पर आप अधिकतर संभावना जादू संकेतक का पुन: उपयोग नहीं कर सकते हैं – 3.8 / 5-7 के कारण फिर से।

किसी ऑब्जेक्ट के बाइट्स को पढ़ना (यह char या unsigned char का उपयोग करने का अर्थ है) ठीक है, और आप reinterpret_cast या कुछ जादू भी इस्तेमाल नहीं कर सकते। cv void* माध्यम से static_cast नौकरी के लिए यकीनन ठीक है (हालांकि मुझे ऐसा लगता है कि मानक कुछ बेहतर शब्द इस्तेमाल कर सकता है)।

यह भी:

 // valid: char -> type alignas(int) char c[sizeof(int)]; int * i = reinterpret_cast<int*>(c); 

वह सही नहीं है। अलियासिंग नियमों के तहत एक परिस्थिति के तहत एक अलग प्रकार के लार्वेल के माध्यम से एक वस्तु का उपयोग करने के लिए कानूनी / अवैध है। एक विशिष्ट नियम है जो कहता है कि आप किसी भी ऑब्जेक्ट को किसी प्रकार के char या unsigned char माध्यम से एक्सेस कर सकते हैं, इसलिए पहला मामला सही है। यह है, ए => बी का मतलब जरूरी नहीं है कि बी => ए। आप को char एक सूचक के माध्यम से एक int तक पहुंच सकते हैं, लेकिन आप किसी सूचक को int माध्यम से char नहीं पहुंच सकते।


अल्फ के लाभ के लिए:

यदि कोई प्रोग्राम किसी ऑब्जेक्ट के संग्रहीत मूल्य को निम्न प्रकारों में से एक के अलावा अन्य के ग्लव्यू के माध्यम से एक्सेस करने का प्रयास करता है तो व्यवहार अनिर्धारित है:

  • वस्तु का गतिशील प्रकार,
  • ऑब्जेक्ट के डायनामिक प्रकार का एक सीवी-योग्य संस्करण,
  • ऑब्जेक्ट के डायनेमिक प्रकार को एक प्रकार समान (जैसा कि 4.4 में परिभाषित किया गया है)
  • एक प्रकार जो ऑब्जेक्ट के डायनेमिक प्रकार से संबंधित हस्ताक्षरित या अहस्ताक्षरित प्रकार है,
  • एक प्रकार जो हस्ताक्षरित या अहस्ताक्षरित प्रकार वस्तु के गतिशील प्रकार के सीवी-योग्य संस्करण के अनुरूप होता है,
  • एक समग्र या यूनियन प्रकार जिसमें इसके तत्वों या गैर-स्थिर डेटा सदस्यों में से एक में से एक को शामिल किया गया है (जिसमें, एक पुनरावर्ती, एक तत्व या गैर-स्थैतिक डेटा सदस्य, एक सबगैगेट या संघ शामिल है)
  • ऑब्जेक्ट के डायनामिक प्रकार के एक प्रकार (संभवतः सीवी-योग्य) बेस क्लास प्रकार है,
  • एक चार या अहस्ताक्षरित चार प्रकार

की वैधता के बारे में …

 alignas(int) char c[sizeof(int)]; int * i = reinterpret_cast<int*>(c); 

कंपाइलर के आधार पर, एक उपयुक्त सूचक मूल्य का निर्माण करने की भावना में, reinterpret_cast ही ठीक है या नहीं। और इस उदाहरण में परिणाम का उपयोग नहीं किया जाता है, विशेष रूप से, वर्ण सरणी का उपयोग नहीं किया जाता है। तो ऐसा कुछ नहीं है जो उदाहरण के बारे में कहा जा सकता है: यह सिर्फ निर्भर करता है

लेकिन आइए एक विस्तारित संस्करण पर विचार करें जो अलियासिंग नियमों पर स्पर्श करता है:

 void foo( char* ); alignas(int) char c[sizeof( int )]; foo( c ); int* p = reinterpret_cast<int*>( c ); cout << *p << endl; 

और चलो केवल उस मामले पर विचार करें जहां कंपाइलर एक उपयोगी पॉइंटर मान की गारंटी देता है, जो कि स्मृति के समान बाइट्स में पॉइन्टेई रखता है (कारण यह कि संकलक पर निर्भर करता है कि मानक, §5.2.10 / 7 में, केवल इसे पॉन्टर रूपांतरण के लिए गारंटी देता है जहां प्रकार संरेखण-संगत हैं, और अन्यथा इसे "अनिर्दिष्ट" के रूप में छोड़ दें (लेकिन तब, §5.2.10 का संपूर्ण § 9.2 / 18 के साथ कुछ असंगत है)।

अब, मानक के §3.10 / 10 के एक व्याख्या, तथाकथित "सख्त अलियासिंग" खंड (लेकिन ध्यान दें कि मानक शब्द "सख्त अलियासिंग" शब्द का प्रयोग नहीं करते हैं),

यदि कोई प्रोग्राम किसी ऑब्जेक्ट के संग्रहीत मूल्य को निम्न प्रकारों में से एक के अलावा अन्य के ग्लव्यू के माध्यम से एक्सेस करने का प्रयास करता है तो व्यवहार अनिर्धारित है:

  • वस्तु का गतिशील प्रकार,
  • ऑब्जेक्ट के डायनामिक प्रकार का एक सीवी-योग्य संस्करण,
  • ऑब्जेक्ट के डायनेमिक प्रकार को एक प्रकार समान (जैसा कि 4.4 में परिभाषित किया गया है)
  • एक प्रकार जो ऑब्जेक्ट के डायनेमिक प्रकार से संबंधित एक हस्ताक्षरित या अहस्ताक्षरित प्रकार है,
  • एक प्रकार जो हस्ताक्षरित या अहस्ताक्षरित प्रकार वस्तु के गतिशील प्रकार के सीवी-योग्य संस्करण के अनुरूप होता है,
  • एक समग्र या यूनियन प्रकार जिसमें इसके तत्वों या गैर-स्थिर डेटा सदस्यों में से एक में से एक को शामिल किया गया है (जिसमें पुनरावृत्त रूप से, किसी तत्व या गैर-स्थिर डेटा सदस्य को एक सबगैगेट या संघ में शामिल किया गया है),
  • ऑब्जेक्ट के डायनामिक प्रकार के एक प्रकार (संभवतः सीवी-योग्य) बेस क्लास प्रकार है,
  • एक char या unsigned char प्रकार

यह है कि, जैसा कि यह स्वयं कहता है, c बाइट में रहते हुए वस्तु का गतिशील प्रकार की चिंता करता है।

उस व्याख्या के साथ, *p पर पढ़ने का कार्य ठीक है अगर foo ने वहां एक int वस्तु रखी है, और अन्यथा नहीं। तो इस मामले में, एक char सरणी को int* सूचक के माध्यम से पहुंचाया जाता है और कोई भी किसी भी संदेह में नहीं है कि दूसरा तरीका मान्य है: भले ही foo ने उन बाइट्स में एक int ऑब्जेक्ट रखा हो, फिर भी आप उस ऑब्जेक्ट को §3.10 / 10 के आखिरी डैश द्वारा char मूल्यों के अनुक्रम के रूप में आसानी से एक्सेस कर सकते हैं

तो इस (सामान्य) व्याख्या के साथ, foo बाद एक int वहाँ रखा है, हम इसे char वस्तुओं के रूप में उपयोग कर सकते हैं, तो कम से कम एक char वस्तु का नाम स्मृति क्षेत्र के भीतर मौजूद है; और हम इसे int रूप में एक्सेस कर सकते हैं, इसलिए कम से कम एक int मौजूद है; और इसलिए दाऊद का यह दावा है कि char वस्तुओं को int रूप में उपयोग नहीं किया जा सकता है, इस सामान्य व्याख्या के साथ असंगत है।

दाऊद का दावा भी नियुक्ति के सबसे आम उपयोग के साथ असंगत है नया।

क्या अन्य संभव व्याख्याओं के बारे में हैं, शायद दाऊद के तर्क के साथ संगत हो सकता है, ठीक है, मैं किसी भी अर्थ के बारे में सोच नहीं सकता।

तो निष्कर्ष में, जहां तक ​​पवित्र मानक का संबंध है, केवल खुद को T* पॉइंटर को ढंककर सरणी में व्यावहारिक रूप से उपयोगी है या न ही कंपाइलर पर निर्भर करता है, और इंगित किया जा सकता है कि हो सकता है कि मूल्य मान्य है या नहीं वर्तमान। विशेष रूप से, अंतर के एक जाल प्रत्यायन के बारे में सोचें: आप चाहते हैं कि आप पर उड़ा न दें, यदि बिपाशाणु ऐसा हुआ हो। तो सुरक्षित होने के लिए आपको पता होना चाहिए कि इसमें क्या है, बिट्स, और ऊपर दिए गए foo को कॉल के रूप में दिखाता है कि कंपाइलर सामान्य रूप से नहीं जानता कि , जैसे, जी ++ कंपाइलर का सख्त संरेखण-आधारित अनुकूलक सामान्य रूप से यह नहीं जान सकता कि …