2013-08-04 4 views
9

यह एक आम पैटर्न है जिसे मैं इंडेक्स टोकन के रूप में उपयोग करने के लिए उपयोग करता हूं: जांच करें कि टोकन मानचित्र में है या नहीं, और यदि नहीं, तो मानचित्र के आकार को निर्दिष्ट करने के लिए इसे मानचित्र में जोड़ें।किसी आकार के मानचित्र को उसके आकार में सेट करने से आकार * पहले * इसे आवंटित क्यों करता है?

जब सी ++ में यह कर, यह अप्रत्याशित रूप से नक्शे के आकार से पहले काम किया जाता है वृद्धि कर देता है:

#include <cstdio> 
#include <map> 
using namespace std; 

int main() { 
    map<char, int> m; 
    printf("Size before adding: %d\n", m.size()); 
    m['A'] = m.size(); 
    printf("Size after adding: %d\n", m.size()); 
    printf("What was added: %d\n", m['A']); 

    return 0; 
} 

यह बाहर प्रिंट:

Size before adding: 0 
Size after adding: 1 
What was added: 1 

तरह से मैं यह समझते हैं, यह होना चाहिए दाईं ओर का मूल्यांकन करें, जो शून्य है, फिर उसे उस फ़ंक्शन पर पास करें जो 'ए' और शून्य को मानचित्र में रखता है। लेकिन ऐसा लगता है कि इसे असाइन करना शुरू करने के बाद इसका मूल्यांकन किया जा रहा है, जो समझ में नहीं आता है।

असाइनमेंट ऑपरेशन से पहले दाएं हाथ की तरफ मूल्यांकन नहीं किया जाना चाहिए?

+0

नहीं, मुझे यकीन है कि यह यूबी है। – Borgleader

+1

@ बॉर्गलीडर: यह अनिर्दिष्ट व्यवहार है। – Nawaz

+0

@ नवाज ओह सही, निर्दिष्ट – Borgleader

उत्तर

6

व्यवहार अनिश्चित, पैडेंटिक रूप से बोल रहा है।

लेकिन क्या अपने मामले में क्या होता है यह है:

m['A'] = m.size(); 

m एक std::map जो एक नई प्रविष्टि यदि कुंजी मौजूद नहीं है बनाता है।

आपके मामले में, कुंजी 'A' मौजूद नहीं है, तो यह प्रविष्टि बनाता है, और जिसके परिणामस्वरूप आपके मामले में m.size() के लिए निर्दिष्ट मान के संदर्भ में (जो डिफ़ॉल्ट बनाई गई है) वापस जाएँ।

ऊपर बताए अनुसार, व्यवहार निर्दिष्ट नहीं है, क्योंकि ऑपरेटरों के मूल्यांकन के आदेश को निर्दिष्ट नहीं किया गया है जिसका अर्थ है m.size() का मूल्यांकन m['A'] से पहले किया जा सकता है। यदि ऐसा होता है, तो m['A']0 होगा, 1 नहीं।

+2

ठीक है, इसलिए ऑपरेशंस के मूल्यांकन का आदेश अनिश्चित * सामान्य रूप से * सी ++ में है? –

+1

@EvgeniSergeev: हाँ, यह सभी ऑपरेटरों के लिए सच है, ** ** कॉमा ऑपरेटर को छोड़कर, 'इस मामले में आदेश को बाएं से दाएं होने के लिए परिभाषित किया गया है। – Nawaz

+4

... और 'या' ('||'), 'और' ('&&') ऑपरेटरों के लिए भी ऑर्डर परिभाषित किया गया है। – iammilind

4

लेकिन यह यह मूल्यांकन कर होने के बाद यह बताए शुरू कर दिया है ...

काम में मूल्यांकन के आदेश वास्तव में अनिर्दिष्ट है (बाएं हाथ या दाएँ हाथ अभिव्यक्ति पहले मूल्यांकन किया जाता है कि क्या अनिर्दिष्ट है), जैसा कि this question के उत्तरों से संकेत मिलता है।

यदि m.size() का मूल्यांकन पहले किया गया है, तो आपका कोड इरादे के अनुसार काम करेगा, लेकिन आपको इस व्यवहार की गारंटी नहीं है, और दूसरा कार्यान्वयन m['A'] का मूल्यांकन कर सकता है, वही मामला आपके साथ। इन संदिग्ध मामलों से बचा जाना चाहिए।

बेहतर यह बजाय

auto size = m.size(); 
m['A'] = size; 

जो आप की गारंटी है कि आकार क्वेरी तत्व काम करने से पहले मूल्यांकन किया जाता है की तरह कुछ है।

LIVE CODE with the improvement.

4

सं।

(§5।17/1): "सभी मामलों में, असाइनमेंट को दाएं और बाएं ऑपरेटरों की मान गणना के बाद अनुक्रमित किया जाता है, और असाइनमेंट अभिव्यक्ति की मान गणना के पहले।"

नोट, हालांकि, दाएं और बाएं ऑपरेटरों के मूल्यांकन के बाद असाइनमेंट होता है, बाएं और दाएं ऑपरेटरों के मूल्यांकन के बीच कोई अनुक्रम निर्दिष्ट नहीं होता है। इसलिए, बाएं पहले मूल्यांकन किया जा सकता है, फिर दाएं, या इसके विपरीत।

1

यह [] ऑपरेटर, की अनुमानित कार्यान्वयन एसटीएल हेडर फाइल से संपादित

mapped_type& operator[](const key_type& key){ 
auto itr = lower_bound(key); 
// itr->first is greater than or equivalent to key. 
if (itr == end() || comp_func(key, (*itr).first)) 
     itr = insert(itr, value_type(key, mapped_type())); 
return (*itr).second; 
} 

तो जैसा कि आप देख सकते हैं नए तत्व यह पहली बार सम्मिलित करता है के लिए है, जिससे द्वारा 1

रेफरी std::map::operator[] नक्शे का आकार बढ़ जाता है

यदि कुंजी कंटेनर में किसी भी तत्व की कुंजी से मेल नहीं खाती है, तो फ़ंक्शन उस कुंजी के साथ एक नया तत्व सम्मिलित करता है और इसके मैप किए गए मान पर संदर्भ देता है। ध्यान दें कि यह हमेशा कंटेनर आकार को एक से बढ़ाता है, भले ही कोई मैप किए गए मान तत्व को असाइन नहीं किया गया हो ( तत्व अपने डिफ़ॉल्ट कन्स्ट्रक्टर का उपयोग करके बनाया गया है)।

संपादित करें:

के रूप में दूसरों के द्वारा कहा, m['A'] = m.size();, एक अनिर्दिष्ट व्यवहार की ओर जाता है इस तरह के बयानों का उपयोग कभी नहीं, इसके बजाय आप आकार पहले की गणना और फिर नए कुंजी को असाइन कर सकें।

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