2016-02-12 4 views
14

मान लीजिए मैं एक समारोह है, इस तरह कहा जाता है:है और एआर [आकार] वैध है?

void mysort(int *arr, std::size_t size) 
{ 
    std::sort(&arr[0], &arr[size]); 
} 

int main() 
{ 
    int a[] = { 42, 314 }; 
    mysort(a, 2); 
} 

मेरा प्रश्न है: mysort का कोड (खासतौर पर, &arr[size]) व्यवहार को परिभाषित किया है करता है?

मुझे पता है कि arr + size द्वारा प्रतिस्थापित किया गया है तो यह पूरी तरह वैध होगा; पॉइंटर अंकगणित सामान्य रूप से अतीत को इंगित करने की अनुमति देता है। हालांकि, मेरा प्रश्न विशेष रूप से & और [] के उपयोग के बारे में है।

प्रति सी ++ 11 5.2.1/1, arr[size]*(arr + size) के बराबर है।

5.3.1/1 का हवाला देते हुए, एकल * के लिए नियम: अभिव्यक्ति के लिए जो इसे एक ऑब्जेक्ट प्रकार करने के लिए एक सूचक होगा लागू किया जाता है, या:

एकल * ऑपरेटर अविवेक करता है फ़ंक्शन प्रकार के लिए पॉइंटर और परिणाम ऑब्जेक्ट या पर संदर्भित एक लवली है जिसमें अभिव्यक्ति इंगित करती है। अगर अभिव्यक्ति के प्रकार है "सूचक T के लिए," परिणाम के प्रकार के "T है।" [नोट: एक अधूरी प्रकार (सीवीvoid को छोड़कर) के लिए सूचक dereferenced जा सकता है। इस प्रकार प्राप्त किया गया लाभा सीमित तरीकों से उपयोग किया जा सकता है (उदाहरण के लिए संदर्भ शुरू करने के लिए); यह lvalue प्रसार में परिवर्तित नहीं किया जाना चाहिए, 4.1 देखें। अंत टिप्पणी]

अंत में, 5.3.1/3 & के लिए नियमों को दे रही है:

एकल & ऑपरेटर का परिणाम अपने संकार्य के लिए सूचक है। ऑपरेंड एक लवल्यू होगा ... यदि का प्रकार T है, तो परिणाम "सूचक से T" टाइप किया गया है और यह एक अनुमान है कि नामित ऑब्जेक्ट (1.7) या पॉइंटर के लिए एक सूचक है नामित समारोह

(जोर और अंडाकार खान)।

मैं इस बारे में अपना मन बिल्कुल तैयार नहीं कर सकता। मुझे यकीन है कि arr[size] पर एक लवली-टू-रावल्यू रूपांतरण को मजबूर करना अनिर्धारित होगा। लेकिन कोड में ऐसा कोई रूपांतरण नहीं होता है। arr + size किसी ऑब्जेक्ट को इंगित नहीं करता है; लेकिन उपरोक्त पैराग्राफ ऑब्जेक्ट्स के बारे में बात करते हैं, लेकिन वे किसी ऑब्जेक्ट के लिए उस स्थान पर वास्तव में मौजूद होने की आवश्यकता को स्पष्ट रूप से प्रकट नहीं करते हैं (उदाहरण के विपरीत 4.1/1 में lvalue-to-rvalue रूपांतरण)।

तो, खोज है: mysort है, जिस तरह से इसे वैध या नहीं कहा जाता है?

(ध्यान दें कि मैं उपरोक्त सी ++ 11 उद्धृत कर रहा हूं, लेकिन यदि इसे बाद के मानक/ड्राफ्ट में अधिक स्पष्ट रूप से संभाला जाता है, तो मैं इसके साथ पूरी तरह से खुश हूं)।

+0

कोई डुप्लिकेट नहीं है, @ एंज्यू जानता है कि: मेरा विश्वास करो। – Bathsheba

+0

निश्चित नहीं है लेकिन [basic.compound] अनुच्छेद 3 * में नोट के बारे में क्या है [नोट: उदाहरण के लिए, किसी सरणी (5.7) के अंत में वाला पता सरणी के तत्व की एक असंबंधित वस्तु को इंगित करने के लिए माना जाएगा टाइप करें जो उस पते पर स्थित हो सकता है। गतिशील भंडारण अवधि वाले ऑब्जेक्ट्स पर पॉइंटर्स पर और प्रतिबंध हैं; 3.7.4.3 देखें। -जेंड नोट] * – NathanOliver

+3

क्या कोई मुझे बता सकता है कि संभावित डुप्लिकेट की तुलना में इस प्रश्न में नया क्या है? ऐसा लगता है कि वहां से जवाब की प्रतिलिपि बनाने से वास्तव में इस प्रश्न का उत्तर भी मिलेगा। –

उत्तर

9

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

सी में, यह एक दोष करार दिया गया था और तय ताकि कल्पना अब &*ptr में कहते हैं, न तो & है और न ही * का मूल्यांकन किया जाता है। सी ++ को अभी तक निश्चित शब्द नहीं मिला है। यह एक बहुत पुराना अभी भी सक्रिय डीआर का विषय है: DR #232। इरादा यह है कि यह मान्य है, जैसा कि यह सी में है, लेकिन मानक ऐसा नहीं कहता है।

+0

शब्द "वैध" को स्पष्ट करने की आवश्यकता है। अभिव्यक्ति का पता या मान पूरी तरह मान्य है। हालांकि, उस स्थान पर आइटम तक पहुंच अपरिभाषित व्यवहार है। –

+3

@ थॉमस मैथ्यूज मेरे उत्तर का पूरा बिंदु यह है कि जब आप कहते हैं कि इसका क्या इरादा है, यह * नहीं * मानक कहता है। – hvd

+0

मुझे यकीन नहीं था कि "ऑब्जेक्ट एक्स जिसके लिए पी (एक्स)" का अर्थ "यदि पी (एक्स) तो x else ??" (जो मूल रूप से प्रश्न का सार था), लेकिन डीआर का अस्तित्व दृढ़ता से सुझाव देता है, या कम से कम दिखाता है कि इस मुद्दे को संबोधित करने की आवश्यकता है। डीआर, मेरे लिए इसे साफ़ करता है, धन्यवाद। – Angew

-5

यह पूरी तरह ठीक और अच्छी तरह से परिभाषित है जब तक कि आकार वास्तविक सरणी (सरणी तत्वों की इकाइयों में) के आकार से बड़ा नहीं है।

तो यदि मुख्य() माईसॉर्ट (ए, 100), & एआर [आकार] कहा जाता है तो पहले से ही अपरिभाषित व्यवहार होगा (लेकिन सबसे अधिक संभावना ज्ञात नहीं है, लेकिन std :: sort स्पष्ट रूप से गलत भी गलत हो जाएगा)।

+1

से सी टैग जोड़ा लेकिन उनका मुद्दा यह है कि 'arr [size] 'dereferences value सरणी सीमाओं से बाहर। –

+0

@ TomášZato: नहीं, यह सीमा से बाहर नहीं है। –

1

सामान्य सी ++ सरणी के संदर्भ में, हाँ। सरणी के एक-अतीत के अंत तत्व का पता बनाना कानूनी है। यह इंगित करने के लिए कानूनी नहीं है कि यह क्या इंगित कर रहा है, हालांकि (आखिरकार, वहां कोई वास्तविक तत्व नहीं है)। तो जब आप &arr[size] करते हैं, तो arr[size] एक-अतीत-अंत तत्व के संदर्भ के रूप में आप क्या सोच सकते हैं, लेकिन वास्तव में उस तत्व तक पहुंचने की कोशिश नहीं की है। फिर & आपको उस तत्व का पता प्राप्त करता है। चूंकि कुछ भी वास्तव में उस सूचक का पालन करने की कोशिश नहीं कर रहा है, कुछ भी बुरा नहीं हुआ है।

यह दुर्घटना से नहीं है, यह संकेतकों को तीरंदाजों की तरह व्यवहार करता है। इस प्रकार &a[0] सरणी पर .begin() आवश्यक है, और &a[size] (जहां आकार सरणी में तत्वों की संख्या है) अनिवार्य रूप से .end() है। (यह भी देखें std::array जहां यह अधिक स्पष्ट हो रहा है)

संपादित करें: एआरएम, मुझे यह जवाब वापस लेना पड़ सकता है। हालांकि यह ज्यादातर मामलों में लागू होता है, यदि सरणी में संग्रहीत प्रकार को operator& पर ओवरराइड किया गया है, तो &a[size] पर, operator& विधि a[size]पर प्रकार के उदाहरण के सदस्यों तक पहुंचने का प्रयास कर सकती है, जहां कोई उदाहरण नहीं है।

0

मान लीजिए size वास्तविक सरणी आकार है, तो आप std::sort() पर पिछले-अंत तत्व को पॉइंटर पास कर रहे हैं।

तो, जैसा कि मैं इसे समझता हूं, सवाल नीचे उबलता है: क्या यह सूचक arr.end() के बराबर है?

इसमें कोई संदेह नहीं है कि यह प्रत्येक मौजूदा कंपाइलर के लिए सच है, क्योंकि सरणी इटरेटर वास्तव में पुराने पुराने पॉइंटर्स हैं, इसलिए &arr[size]arr.end() के लिए स्पष्ट विकल्प है।

हालांकि, मुझे संदेह है कि सादे पुराने सरणी इटरेटर के वास्तविक कार्यान्वयन के बारे में एक विशिष्ट आवश्यकता है।

तो, तर्क की खातिर, आप एक संकलक वास्तविक पते के अलावा एक "पिछले अंत" बिट का उपयोग सादे पुराने सरणी iterators आंतरिक रूप से लागू करने के लिए कल्पना कर सकता और विकृत अपने मूंछें गुलाबी रंग अगर यह किसी भी पता लगाया पॉइंटर अंकगणित के माध्यम से प्राप्त iterators और पते के बीच concievable असंगतता। यह अजीब संकलक वास्तव में spec का उल्लंघन किए बिना क्रैश करने के लिए बहुत सारे मौजूदा C++ कोड का कारण बनता है, जो इसे डिजाइन करने के प्रयास के लायक हो सकता है ...

0

अगर हम स्वीकार करते हैं कि arr[i] सिर्फ *(arr + i) के लिए एक आशुलिपि है, हम &*(arr + size) रूप &arr[size] पुनर्लेखन कर सकते हैं। इसलिए, हम एक सूचक को संदर्भित कर रहे हैं जो पिछले-अंत-अंत तत्व को इंगित करता है, जो एक अपरिभाषित व्यवहार की ओर जाता है। जैसा कि आप सही ढंग से कहते हैं, arr + size बदले में कानूनी होगा, क्योंकि कोई डेरफ़्रेंसिंग ऑपरेशन नहीं होता है।

संयोग से, यह स्टेपानोव के notes (पृष्ठ 11) में एक प्रश्नोत्तरी के रूप में भी प्रस्तुत किया जाता है।

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