2011-08-03 21 views
7

एक std::map से अधिक पुनरावृति करने के लिए कैसे दिखा उदाहरण ऐसा अक्सर कर रहे हैं:++ या यह ++ मानचित्र पर पुनरावृत्ति करते समय?

MapType::const_iterator end = data.end(); 
for (MapType::const_iterator it = data.begin(); it != end; ++it) 

यानी यह ++it बजाय it++ उपयोग करता है। क्या कोई कारण है? अगर मैं it++ का उपयोग करता हूं तो क्या कोई समस्या हो सकती है?

+0

[इस] [1] पर एक नज़र डालें। [1]: http://stackoverflow.com/questions/24853/c-what-is-the-difference-between-i-and-i – sergio

+5

अगर आप समय के किसी भी लम्बाई के लिए C++ कोड , '++ यह' दक्षता के लिए एक महत्वपूर्ण बढ़ावा प्रदान करेगा। आपके कोड में नहीं, लेकिन समय में लोगों को समझाते हुए आपने पहली बार '++ इसे' क्यों नहीं किया। चूंकि यह वास्तव में मामूली बात नहीं करता है, इसलिए आप ऐसा भी कर सकते हैं जिससे तर्क नहीं आएंगे। –

+0

@ डेनिस: इससे कोई फर्क नहीं पड़ता * बहुत * और अक्सर मापने योग्य नहीं होगा, लेकिन तंग लूप में, इससे कोई फर्क पड़ सकता है। –

उत्तर

10

परीक्षण करने के लिए यह लाना, मैं तीन स्रोत फ़ाइलें बनाया:

#include <map> 

struct Foo { int a; double b; char c; }; 

typedef std::map<int, Foo> FMap; 

### File 1 only ### 

void Set(FMap & m, const Foo & f) 
{ 
    for (FMap::iterator it = m.begin(), end = m.end(); it != end; ++it) 
    it->second = f; 
} 

### File 2 only ### 

void Set(FMap & m, const Foo & f) 
{ 
    for (FMap::iterator it = m.begin(); it != m.end(); ++it) 
    it->second = f; 
} 

### File 3 only ### 

void Set(FMap & m, const Foo & f) 
{ 
    for (FMap::iterator it = m.begin(); it != m.end(); it++) 
    it->second = f; 
} 

### end ### 

g++ -S -O3 साथ संकलन के बाद, जीसीसी 4.6.1, मुझे लगता है कि संस्करण 2 और 3 का उत्पादन समान विधानसभा, और संस्करण 1 अलग है केवल एक निर्देश में, cmpl %eax, %esi बनाम cmpl %esi, %eax

तो, अपना चयन करें और अपनी शैली के अनुरूप जो भी उपयोग करें। उपसर्ग वृद्धि ++it शायद सबसे अच्छा है क्योंकि यह आपकी आवश्यकताओं को सबसे सटीक रूप से व्यक्त करता है, लेकिन इसके बारे में लटका नहीं है।

+1

अनुकूलन का अच्छा प्रदर्शन, लेकिन यह केवल पर्याप्त सरल और रेखांकित 'ऑपरेटर ++' के लिए काम कर सकता है। G ++ देखने के लिए अच्छा यह 'std :: map' के लिए कर सकता है। –

+1

@ क्रिस्टोफर: हाँ, और जब आप इसका मतलब रखते हैं तो आपको निश्चित रूप से हमेशा '++ इसे' का उपयोग करना चाहिए। मुझे लगता है कि दो ऑफ-विज्ञापित बिंदुओं (अंत में उछाल और उपसर्ग वृद्धि का उपयोग करके) के वास्तविक प्रभाव पर कुछ कठिन तुलना प्रदान करना। –

20

it++ पिछले पुनरावर्तक की एक प्रति देता है। चूंकि इस इटरेटर का उपयोग नहीं किया जाता है, यह अपमानजनक है। ++it कॉपी से परहेज करते हुए, वृद्धिशील इटरेटर का संदर्भ देता है।

कृपया एक पूर्ण स्पष्टीकरण के लिए Question 13.15 देखें।

+4

यह शायद ही कोई फर्क नहीं पड़ता। मुद्दा पूरी तरह से शैली का है। –

+1

@ डार्क - चूंकि इसका उपयोग नहीं किया जाता है, इसलिए संकलक इसे नोटिस करने और प्रतिलिपि को अनुकूलित करने की संभावना है। –

+2

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

7

पोस्ट-वृद्धि ऑपरेटर बनाम पूर्व-वृद्धि ऑपरेटर का उपयोग करने में थोड़ा सा performance advantage है। छोरों कि iterators का उपयोग स्थापित करने में, आप पहले से वेतन वृद्धि का उपयोग करने का विकल्प चुन चाहिए: जब आप के बारे में कैसे दोनों ऑपरेटरों आम तौर पर किया जाएगा implemented.The पूर्व वेतन वृद्धि काफी सरल है लगता है

for (list<string>::const_iterator it = tokens.begin(); 
    it != tokens.end(); 
    ++it) { // Don't use it++ 
    ... 
} 

कारण प्रकाश में आने पर।

class MyInteger { 
private: 
    int m_nValue; 

public: 
    MyInteger(int i) { 
     m_nValue = i; 
    } 

    // Pre-increment 
    const MyInteger &operator++() { 
     ++m_nValue; 
     return *this; 
    } 

    // Post-increment 
    MyInteger operator++(int) { 
     MyInteger clone = *this; // Copy operation 1 
     ++m_nValue; 
     return clone; // Copy operation 2 
    } 
} 

पोस्ट आप देख सकते हैं, हालांकि, काम करने के लिए के बाद वेतन वृद्धि के लिए आदेश में, आप पहली बार, वस्तु की एक प्रतिलिपि बनाने मूल वस्तु पर वास्तविक वेतन वृद्धि करना और उसके बाद प्रति वापस जाने के लिए की जरूरत है - कार्यान्वयन कार्यान्वयन में दो अतिरिक्त प्रति संचालन शामिल हैं। यदि प्रश्न में वस्तु भारी है तो यह काफी महंगा हो सकता है। ऐसा कहकर, कुछ कंप्यूटर्स ऑप्टिमाइज़ेशन के माध्यम से एक प्रतिलिपि ऑपरेशन से दूर होने के लिए पर्याप्त स्मार्ट हो सकते हैं। मुद्दा यह है कि एक पोस्ट-वृद्धि में आम तौर पर पूर्व-वृद्धि के मुकाबले अधिक काम शामिल होगा और इसलिए आपके "++" को आपके इटरेटर्स के सामने रखने के बजाय उपयोग करना बुद्धिमानी है।

(1) लिंक की गई वेबसाइट पर क्रेडिट।

6

तार्किक बिंदु पर - यह वही है और इससे कोई फर्क नहीं पड़ता

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

एक बहुत बड़ा मौका है, कि संकलक इसे अनुकूलित करेगा।


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

अच्छा, यह करने के लिए एक भयानक बात है, लेकिन फिर भी संभव है।

+0

वास्तव में एक भयानक बात है। डेटा को स्ट्रीम में रखने के लिए शिफ्ट ऑपरेटर का दुरुपयोग करने की तरह कुछ, सही? ;-) (एससीएनआर) –

+0

अच्छा, यह एक अच्छा मुद्दा है - आखिरकार, आप अंततः एक कस्टम इटरेटर से निपट सकते हैं जो कि किसी भी कारण से कॉपी करने के लिए बहुत महंगा है और इसे अनुकूलित नहीं किया जा सकता है, इसलिए केवल वही लिखना जो आपका मतलब है ('++ it') जो आपने प्राप्त किया हो, उसके बजाय ('C++') केवल अच्छा अभ्यास है। –

+0

@ केरेक एसबी - बिल्कुल :) मैं हमेशा '++ bla_bla' पसंद करता हूं, जब इसका उपयोग करना ठीक है। –

1

इससे कोई समस्या नहीं आएगी, लेकिन ++it का उपयोग करना अधिक सही है।छोटे प्रकार के साथ यह वास्तव में ++i या i++, लेकिन "बड़ी" कक्षाओं के लिए उपयोग करने के लिए कोई प्रभाव नहीं पड़ेगा:

operator++(type x,int){ 
    type tmp=x; //need copy 
    ++x; 
    return tmp; 
} 

संकलक उनमें से कुछ बाहर का अनुकूलन कर सकते हैं, लेकिन यह सुनिश्चित करने के लिए मुश्किल है।

1

जैसा कि अन्य उत्तरों ने कहा है, इसे ++ पसंद करें जब तक कि यह संदर्भ में काम नहीं करेगा। छोटे प्रकार के कंटेनर पर पुनरावृत्त करने के लिए यह वास्तव में थोड़ा अंतर बनाता है (या कंपाइलर इसे दूर करने में कोई फर्क नहीं पड़ता), लेकिन बड़े प्रकार के कंटेनरों के लिए यह प्रतिलिपि बनाने की लागत को बचाने के कारण एक अंतर डाल सकता है।

सच है, आप अपने विशिष्ट संदर्भ में जान सकते हैं कि प्रकार इतना छोटा है ताकि आप इसके बारे में चिंता न करें। लेकिन बाद में, आपकी टीम के किसी अन्य व्यक्ति कंटेनर की सामग्री को बदल सकता है जहां इससे कोई फर्क नहीं पड़ता। इसके अलावा, मुझे लगता है कि खुद को अच्छी आदत में लेना बेहतर होता है, और जब आप जानते हैं कि केवल आपको वृद्धि होनी चाहिए।

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

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