2016-06-03 22 views
6

मैंने खुद को निम्नलिखित प्रश्न से फंस लिया है: क्या यह अनिश्चित व्यवहार का कारण बन सकता है या नहीं?std :: नक्शा ऑपरेटर [] - अपरिभाषित व्यवहार?

std::map<int, int> m; 
m[10] += 1; 

यह संकलित करता है और पूरी तरह से चलता है लेकिन यह कुछ भी साबित नहीं करता है। यह एक आम यूबी उदाहरण i = ++i + i++;operator[] के बाद से दुष्प्रभाव हो लेकिन दूसरी ओर मूल्यांकन के किसी भी क्रम संभालने पर (दाएं और बाएं के लिए बाएं से दाएं) करता है जैसा दिखता है मुझे नक्शे

पी एस का एक ही अंतिम अवस्था के लिए लाता है संभवतः संबंधित: http://en.cppreference.com/w/cpp/language/eval_order

संपादित

क्षमा करें लोग मैं

m[10] = m[10] + 1; 
+0

ऐसे प्रश्न वास्तव में दिखाते हैं कि भाषा अधिक जटिल हो गई है – Slava

+1

यह ** यूबी ** कैसे हो सकता है? – Destructor

+0

@ निर्माता, कृपया संपादन देखें, क्या कुछ बदलता है? – DimG

उत्तर

3

इस बारे में अपरिभाषित कुछ भी नहीं है लिखा जाना चाहिए था। operator[] मानचित्र प्रविष्टि के लिए एक lvalue संदर्भ देता है (जो इसे आवश्यक बनाता है)। फिर आप केवल इस आभासी अभिव्यक्ति को बढ़ा रहे हैं, यानि अंतर्निहित प्रविष्टि।

मूल्यांकन आदेश के नियम नियम बताते हैं कि एक संशोधित असाइन ऑपरेशन के लिए, साइड इफेक्ट दोनों बाएं (यानी नक्शा प्रविष्टि के लिए lvalue संदर्भ) के दायरे के बाद सख्ती से अनुक्रमित किया गया है (यानी स्थिर 1) ऑपरेंड। इस उदाहरण में बिल्कुल कोई अस्पष्टता नहीं है।

अद्यतन: आपके अपडेट किए गए उदाहरण में कुछ भी नहीं बदलेगा। फिर m[10] को संशोधित करने के दुष्प्रभाव को अन्य परिचालनों के बाद सख्ती से अनुक्रमित किया गया है (यानी दाहिने ओर एक लालू के रूप में मूल्यांकन करना, दाईं ओर मूल्यांकन करना और अतिरिक्त प्रदर्शन करना)।

प्रासंगिक अनुक्रमण नियम, cppreference से:

8) पक्ष प्रभाव (बाएं तर्क के संशोधन) की अंतर्निहित असाइनमेंट ऑपरेटर और के सभी में निर्मित यौगिक काम ऑपरेटरों अनुक्रम है मूल्य गणना के बाद (लेकिन साइड इफेक्ट) के दोनों छोड़ दिया और सही तर्क, और इससे पहले कि काम अभिव्यक्ति के मूल्य गणना

(कि लौटने संशोधित वस्तु के संदर्भ से पहले, है) अनुक्रम है
+0

कृपया, संपादन देखें, क्या उत्तर बदलता है? – DimG

+0

शायद मैं सामान्य रूप से गलत तरीके से "पक्ष को प्रभावित करता हूं" वाक्यांश का उपयोग करता हूं, मैं विशेष रूप से कंटेनर संरचना साइड इफेक्ट के बारे में चिंतित था: बायां हाथ-पक्ष भाग किसी भी तरह * मूल्यांकन * होना चाहिए (वह लालसा जिसे हम बदलना चाहते हैं)। यह मूल्यांकन एक महंगी ऑपरेशन है क्योंकि हम मानचित्र पर एक नया मान डालते हैं। कल्पना कीजिए कि इस बल को खोज पेड़ के नीचे भारी रूप से पुन: संतुलित किया जाना है। इसके अलावा, जैसा कि आपने कृपया जवाब दिया है, दाएं हाथ के हिस्से को * मूल्यांकन * किया जाना चाहिए। आपके द्वारा उद्धृत नियम (जैसा कि मैं देख सकता हूं) वैल्यू कंप्यूशन * के आदेश के बारे में कुछ भी नहीं कहता है। – DimG

+0

इसलिए, उद्धृत पृष्ठ के अनुसार, इन वृक्ष संरचना परिवर्तनों में ओवरलैप हो सकता है: "ए और बी के मूल्यांकन अपूर्ण हैं: वे किसी भी क्रम में निष्पादित किए जा सकते हैं और निष्पादन के एक थ्रेड के भीतर ओवरलैप हो सकते हैं, संकलक CPU निर्देशों को अंतःस्थापित कर सकता है जिसमें ए और बी शामिल है) "। जो बदले में व्यवहार को – DimG

0

मुझे पूरा यकीन नहीं है कि आपकी चिंता क्या है (और शायद आपको यह प्रश्न स्पष्ट करना चाहिए कि वह उत्तर पर्याप्त नहीं है), लेकिन m[10] += 1; का अनुवाद m[10] = m[10] + 1; पर नहीं किया गया है क्योंकि m उपयोगकर्ता परिभाषित वर्ग प्रकार और ओवरलोडेड ऑपरेटर डॉन ' कभी संकलक द्वारा अनुवादित नहीं किया जाता है। एक उपयोगकर्ता परिभाषित वर्ग प्रकार के साथ a और b वस्तुओं के लिए:

  • a+=b मतलब यह नहीं है a = a + b
  • a!=b!(a==b) मतलब यह नहीं है (जब तक आप ऐसा कर)
(जब तक आप ऐसा कर रहे हैं)

इसके अलावा, फ़ंक्शन कॉल को कभी भी डुप्लीकेट नहीं किया जाता है।

तो m[10] += 1; का मतलब है कि एक बार operator[] ओवरलोड किया गया; वापसी प्रकार एक संदर्भ है, इसलिए अभिव्यक्ति एक लाभा है; फिर lvalue में बिल्टिन ऑपरेटर += लागू करें।

मूल्यांकन समस्या का कोई आदेश नहीं है। मूल्यांकन के कई संभावित आदेश भी नहीं हैं! , vector और deque अनुक्रम अवधारणा के कार्यान्वयन (जहां स्थिति मामलों) कर रहे हैं:

इसके अलावा, आप कि std::map<>::operator[]std::vector<>::operator[] (या std::deque की) की तरह व्यवहार नहीं करता है याद करने के लिए, की जरूरत है क्योंकि map एक पूरी तरह से अलग अमूर्त है

  • std::vector<>::operator[] एक संख्यात्मक सूचकांक लेता है, और मतलब नहीं है अगर इस तरह के सूचकांक वेक्टर का एक तत्व का उल्लेख नहीं करता: लेकिन map एक साहचर्य कंटेनर (जहां "कुंजी" मामलों, नहीं स्थिति) है।
  • std::map<>::operator[] एक कुंजी लेता है (जो किसी भी प्रकार की संतोषजनक मूल बाधाओं हो सकता है) और कोई (कुंजी, मान) जोड़ी बनाएगा यदि कोई भी मौजूद नहीं है।

ध्यान दें कि इस कारण के लिए, std::map<>::operator[] स्वाभाविक एक बदलाव संचालन और इस प्रकार गैर स्थिरांक है, जबकि std::vector<>::operator[] स्वाभाविक संशोधित नहीं किया गया है लेकिन उसके परिणाम में संदर्भ के माध्यम से संशोधन अनुमति दे सकते हैं, और इस प्रकार है, "संक्रामक" स्थिरांक: v[i]v एक गैर-कॉन्स वेक्टर और एक कॉन्स लैवल्यू है यदि v एक कॉन्स वेक्टर है तो एक संशोधित अंतराल होगा।

इसलिए कोई चिंता नहीं, कोड पूरी तरह से परिभाषित व्यवहार है।

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