2012-05-14 13 views
24

मैं std::map::insert के अर्थशास्त्र द्वारा थोड़ा उलझन में हूं। मेरा मतलब है, मैं शिकायत नहीं कर रहा हूं - मानक मानक है और एपीआई जिस तरह से है। फिर भी,सी ++ के एसडीडी मानचित्र के लिए तर्क semantics डालें?

insert होगा

प्रत्येक तत्व डाला कि क्या एक और तत्व एक ही कुंजी मूल्य के साथ कंटेनर में पहले से मौजूद है, यदि हां, तत्व डाला जाता है और इसके मूल्य के लिए मैप किया प्रविष्टि आपरेशन के चेक किसी भी तरह से बदला नहीं है।

और - केवल अपने एकल बहस में संस्करण pair<iterator,bool> insert (const value_type& x); यह भी आपको पता चलेगा कि यह और भी (नई संभवतः अलग-अलग) कुंजी (रों) के लिए मूल्य डाला। जहां तक ​​मैं समझता हूं, अगर कुंजी पहले से मौजूद है तो पुनरावृत्त संस्करण चुपचाप प्रविष्टियों को अनदेखा कर देगा।

मेरे लिए, यह केवल काउंटर अंतर्ज्ञानी है, मुझे उम्मीद है कि मूल्य भाग ओवरराइट किया जाएगा और पुराने मूल्य भाग को डालने पर छोड़ दिया जाएगा। जाहिर है, एसटीएल के डिजाइनरों ने अलग-अलग विचार किया - कोई भी (ऐतिहासिक) तर्क जानता है या मौजूदा अर्थशास्त्र कैसे (अधिक) समझने के बारे में पूरी तरह से स्पष्टीकरण दे सकता है?

उदाहरण द्वारा:

ऐसे std::map के रूप में एक एकल कुंजी के नक्शे में डालने को लागू करने के लिए कुछ बुनियादी तरीके हैं:

  • डालने, की जगह पहले से ही
  • डालने मौजूद रहने पर, अगर पहले से मौजूद है तो अनदेखा करें (यह std :: map का व्यवहार है)
  • डालें, अगर पहले से ही त्रुटि फेंक दें
  • डालने मौजूद है, यूबी अगर पहले से मौजूद है

अब मैं समझ क्यों insert_or_ignore की तुलना में अधिक समझ में आता है कोशिश कर रहा हूँ insert_or_replace (या insert_or_error)!


मैं TC++PL (दुर्भाग्य से मैं केवल जर्मन संस्करण है) की मेरी कॉपी में देखा, और दिलचस्प है, Stroustrup (नक्शा के लिए सूची परिचालन) अध्याय 17.4.1.7 में लिखते हैं: (जर्मन से माफी किसी न किसी अनुवाद)

(...) आम तौर पर, एक परवाह नहीं है कि एक प्रमुख (sic!) नव है डाला जाता है या पहले से ही insert() (...)

को कॉल करने से पहले ही अस्तित्व में

जो मुझे लगता है, केवल सेट करें, और मानचित्र के लिए नहीं, क्योंकि मानचित्र के लिए, यदि प्रदान किया गया मान डाला गया था या पुराना एक मानचित्र में रहता है तो यह काफी अंतर करता है । (यह स्पष्ट रूप से कुंजी के लिए कोई फर्क नहीं पड़ता, क्योंकि वह बराबर है।)


नोट: मैं के बारे में operator[] जानते हैं और मैं Effective STL की मद 24 के बारे में पता है और efficientAddOrUpdate समारोह वहाँ का प्रस्ताव रखा। मैं insert के अर्थशास्त्र में एक तर्क के लिए उत्सुक हूं क्योंकि मैं व्यक्तिगत रूप से उन्हें सहज ज्ञान युक्त पाते हैं।

+5

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

+2

यदि आप प्रतिस्थापित/बनाना चाहते हैं, तो 'ऑपरेटर [] 'का उपयोग करें। – BoBTFish

+0

यहां कुछ कोड है ["बलपूर्वक डालें"] (http://stackoverflow.com/a/8337563/596781) मानचित्र में। –

उत्तर

5

मुझे एक आधिकारिक तर्क के बारे में पता नहीं है लेकिन मैं operator[] के साथ द्वंद्व को नोट करता हूं।

यह स्पष्ट लगता है कि एक डालने के दो जायके चाहते हैं:

  • विशुद्ध रूप से additive
  • additive/विनाशकारी

अगर हम एक सरणी के एक विरल प्रतिनिधित्व के रूप में एक map देखते हैं, तो operator[] की उपस्थिति समझ में आता है। मुझे नहीं पता कि पूर्व-मौजूदा शब्दकोश मौजूद हैं या नहीं और इस वाक्यविन्यास को निर्धारित करें (शायद, क्यों नहीं)।

इसके अलावा, सभी एसटीएल कंटेनरों में insert के कई अधिभार हैं, और इंटरफेस की यह समानता जेनेरिक प्रोग्रामिंग की अनुमति देती है।

इसलिए, हमारे पास एपीआई के लिए कम से कम दो दावेदार हैं: operator[] और insert

अब, C++, अगर आप पढ़ सकते हैं:

array[4] = 5; 

यह है स्वाभाविक रूप से है कि सूचकांक 4 पर सेल की सामग्री के विध्वंस अद्यतन किया गया है। इस प्रकार, यह प्राकृतिक है कि map::operator[] को इस विनाशकारी अद्यतन की अनुमति देने के लिए एक संदर्भ वापस करना चाहिए।

इस बिंदु पर, अब हमें एक पूरी तरह से additive संस्करण की आवश्यकता है, और हमारे पास यह insert विधि है जो आसपास झूठ बोल रही है। क्यों नहीं ?

पाठ्यक्रम एक के operator[] रूप insert एक ही अर्थ विज्ञान दे दिया है सकते हैं और फिर आगे जाना है और शीर्ष पर एक insert_or_ignore विधि लागू। हालांकि यह अधिक काम होता।

इसलिए, जबकि मैं मानता हूँ कि यह आश्चर्य की बात हो सकती है, मुझे लगता है कि मेरी तर्क भी त्रुटिपूर्ण नहीं है और परिस्थितियों हमें यहाँ नेतृत्व कि :)


विकल्प आप प्रस्तावित के बारे में की एक संभावित विश्लेषण किया जा सकता है :

  • डालने, यूबी अगर पहले से मौजूद है

सौभाग्य से, यह नहीं है!

  • डालने, फेंक त्रुटि पहले से मौजूद है, तो

केवल जावा (और डेरिवेटिव) अपवाद-पागल है। सी ++ उस समय में कल्पना की गई थी जहां असाधारण परिस्थितियों के लिए अपवादों का उपयोग किया जाता था।

  • डालने, की जगह पहले से ही
  • डालने मौजूद रहने पर, उपेक्षा पहले से मौजूद है कि क्या (यह std :: नक्शे के व्यवहार है)

हम सहमत हैं कि चुनाव एक के बीच था उन की। ध्यान दें कि भले ही map दूसरे विकल्प को चुना गया है, फिर भी यह को अनदेखा नहीं करता है, यह तथ्य कि आइटम पहले से मौजूद है, कम से कम एक आइटम संस्करण में, क्योंकि यह आपको चेतावनी देता है कि आइटम डाला नहीं गया था।

+0

+1 पर आपका स्वागत है, हालांकि मुझे यकीन नहीं है कि हमें वास्तव में * एक पूरी तरह से additive फ़ंक्शन की आवश्यकता है, क्योंकि हम हमेशा 'ढूंढें()' पहले आ सकते हैं। (दोनों 'डालने' के साथ या तो/या 'सेशन [] ') लेकिन शायद द्वंद्व एक अच्छा कारण था। –

+0

@ मार्टिन: मैं मानता हूं कि एक 'खोज' एक पूरी तरह से additive समारोह बनाने के लिए काम किया होगा। हालांकि इसमें कुछ बॉयलर-प्लेट की आवश्यकता होगी। –

+0

हाँ, रोचक रूप से पर्याप्त, समान बॉयलरप्लेट (या सहायक एफएन) अब आपको एक कुशल insert_or_replace के लिए चाहिए :-) –

0

insert() से आप कंटेनर में मौजूदा वस्तुओं को छूने की उम्मीद नहीं करते हैं। यही कारण है कि यह आसान उन्हें छूता नहीं है।

+1

उत्तर नहीं देता है * यह किसी त्रुटि की रिपोर्ट क्यों नहीं करता है? * प्रश्न का हिस्सा है, लेकिन हाँ यह प्रश्न के एक हिस्से का जवाब देता है। फ़ंक्शन का व्यवहार अपेक्षाकृत सहज है, मौजूदा 'संशोधित करने के लिए' सम्मिलित कॉल की अपेक्षा तत्व बल्कि सहज अंतर्दृष्टि होगी। –

+2

कोई अपराध नहीं था, लेकिन आप समारोह के परिभाषित अर्थशास्त्र को तोड़ रहे हैं, एक तर्क प्रदान नहीं कर रहे हैं। * क्यों * मौजूदा तत्वों को छुआ जाने की उम्मीद नहीं है? क्योंकि इसे "डालने" कहा जाता है और नहीं "insert_or_replace" या क्या? दोबारा, * मेरे लिए * यह सहज ज्ञान युक्त था, और जब मुझे बताया गया कि "नहीं, यह नहीं है" यह समझने में मेरी सहायता नहीं करता है। :-) –

+0

@ मार्टिन: 'insert_or_ignore' (SQLite के रूप में) 'insert_or_replace' से बेहतर नाम नहीं होगा? – dan04

0

pair<iterator,bool> < - क्या बूल हिस्सा नहीं बताता है कि सम्मिलन सफल होता है या नहीं?

यदि आप बूल भाग मौजूदा आइटम को उसी कुंजी के साथ अद्यतन करने के लिए गलत हैं तो आप केवल लौटाए गए इटरेटर के मान भाग को अपडेट कर सकते हैं।

+0

प्रश्न का उल्लेख किया गया। आपने प्रश्न के उस हिस्से को अनदेखा किया है जिसमें 'std :: map :: insert' के अन्य चार अधिभारों का उल्लेख किया गया है। –

7

डालने विधि केवल वही नहीं है जो आप खोज रहे हैं, ऐसा लगता है ... डालने का तरीका केवल उस नाम को करने के लिए किया जाता है जो नाम का तात्पर्य है ... मूल्य डालें। मैं मानता हूं कि कोई मूल्य बनाने की क्षमता अगर कोई पहले से मौजूद नहीं है, और वहां मौजूद किसी अन्य स्थिति में अन्यथा महत्वपूर्ण है, लेकिन दूसरों में आप वास्तव में अपवादों को वापस नहीं करेंगे, मूल्यों को वापस नहीं करेंगे, आदि यदि आप बस केवल एक प्रविष्टि करना चाहते हैं यदि मान पहले से मौजूद नहीं है।

ऐसा लगता है कि आप जिस विधि को खोज रहे हैं (जैसा ऊपर बताया गया है BoBTFish) शायद [] ऑपरेटर है। बस इसे इतना की तरह उपयोग करें:

myMap["key"] = "value"; 

यह आपके मानचित्र के माध्यम से जाने के लिए और कुंजी "कुंजी" मिल जाए, और "मूल्य" के साथ संबंधित मान की जगह लेगा। यदि कुंजी वहां नहीं है, तो यह इसे बनाएगी। दोनों स्थितियों में विभिन्न स्थितियों में बहुत उपयोगी हैं, और मुझे अपनी जरूरतों के आधार पर दोनों का उपयोग करके खुद को मिला है।

+6

मैंने आपकी पोस्ट संपादित की। सबसे पहले, (स्पष्ट रूप से) साइन इन न करें, यह फहरा हुआ है (आपका उपयोगकर्ता अभी भी दिखाई देता है); दूसरा, कृपया इनलाइन कोड स्निपेट और मल्टीलाइन कोड स्निपेट को प्रारूपित करने के तरीके को जानने के लिए मार्कडाउन सिंटैक्स देखें। आपके उत्तर के लिए धन्यवाद और SO :) –

2

मुझे निर्णय के लिए मूल तर्क जानने का दावा नहीं है, लेकिन इसे एक बनाना मुश्किल नहीं है। मुझे लगता है ;-)

"डालने या अनदेखा" का वर्तमान व्यवहार अन्य लोगों को लागू करना बहुत आसान बनाता है - कम से कम उन लोगों के लिए जो उपरोक्त कार्यों को बनाने और गैर-सदस्य कार्यों का उपयोग करने के लिए नहीं हैं मानक पुस्तकालय कार्यक्षमता ("यह ओओपी-वाई पर्याप्त नहीं है!")।

उदाहरण (मौके पर ही लिखा है, तो त्रुटियों मौजूद हो सकता है):

template<typename Map> 
void insert_or_update(Map& map, typename Map::value_type const& x) 
{ 
    std::pair<typename Map::iterator, bool> result = map.insert(x); 
    if (!result.second) 
    result.first->second = x.second; // or throw an exception (consider using 
            // a different function name, though) 
} 

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

किसी भी तरह, map के लिए कोई अन्य सम्मिलित व्यवहार अन्य लोगों को लागू करने के लिए और अधिक कठिन बना देगा, क्योंकि map::find केवल एक अंतिम सेंटीनेल लौटाता है यदि कुंजी पहले से ही मानचित्र में नहीं है। <algorithm> (और विशेष रूप से lower_bound) की सहायता से, यह निश्चित रूप से, कार्यान्वयन विवरण और बदसूरत जेनेरिक संरचनाओं जैसे लूप ;-) के बिना निष्पादित सहायक कार्यों को लिखना संभव होगा।