2013-08-02 6 views
5

सी ++ में किसी वर्ग की विधि से वस्तुओं का संग्रह वापस करने के कई तरीके हैं।संग्रह लौटने पर ट्रेडऑफ

उदाहरण के लिए, क्लास MessageSpy पर विचार करें जो किसी कनेक्शन पर भेजे गए सभी संदेशों पर सुनता है। एक ग्राहक मैसेजिंग जानकारी को कई तरीकों से एक्सेस कर सकता है।

  1. स्थिरांक CollectionClass MessageSpy :: getMessages()
  2. इटरेटर MessageSpy :: शुरू(), इटरेटर MessageSpy :: अंत()
  3. शून्य MessageSpy :: getMessages (OutputIterator)
  4. शून्य MessageSpy :: eachMessage (functor)
  5. दूसरों ...

प्रत्येक दृष्टिकोण अपने व्यापार गत है। उदाहरण के लिए: दृष्टिकोण 1 को पूरे संग्रह की प्रतिलिपि बनाने की आवश्यकता होगी जो बड़े संग्रहों के लिए महंगा है। जबकि दृष्टिकोण 2 कक्षा को एक संग्रह की तरह दिखता है जो दृश्य के लिए अनुचित है ...

चूंकि मैं हमेशा सबसे उपयुक्त दृष्टिकोण चुनने का प्रयास कर रहा हूं, मुझे आश्चर्य है कि आप इन दृष्टिकोणों पर विचार करते समय व्यापार-बंद/लागत पर क्या विचार करते हैं ?

+0

यिक्स, इस प्रश्न की टिप्पणियां गायब हो गईं! "अनिवार्य पेपर" के लिंक के साथ एक टिप्पणी थी। क्या कोई भी लिंक फिर से पोस्ट कर सकता है? धन्यवाद! –

+0

@ क्रिस्टियनअमेर I _think_ यह [यह एक] था (http://c2.com/cgi/wiki?PrematureOptimization)। हालांकि, इंटरवब्स के चारों ओर तैरते हुए एक ही विषय वस्तु के आस-पास कई "मौलिक टुकड़े" हैं। QT डेटा साझाकरण के साथ linq के लिए – sehe

उत्तर

7

मैं उन मामलों में एक इटरेटर आधारित/कॉलबैक आधारित दृष्टिकोण का सुझाव देता हूं जहां आप सबसे हल्के समाधान की मांग करते हैं।

कारण यह है कि यह उपभोक्ता द्वारा उपयोग प्रतिमानों से आपूर्तिकर्ता अलग करता है।

विशेष रूप से, एक संग्रह में परिणाम बंद (यहां तक ​​कि शायद "अनुकूलित" परिणाम यद्यपि - में होने की संभावना (एन) RVO या वस्तु को कॉपी करने की बजाय बढ़ रहा है) अभी भी एक पूर्ण कंटेनर पूरी क्षमता के लिए आवंटित होगा ।

संपादित करें: एक उत्कृष्ट इसके अलावा करने के लिए "अनिवार्य कागजात" (वे नहीं कर रहे हैं, अगर आप चीजों को समझना चाहते हैं वे सिर्फ अविश्वसनीय रूप से उपयोगी हैं): Want Speed? Pass By value डेव इब्राहीम द्वारा।

अब

  • इस overkill है अगर उपभोक्ता वास्तव में पहले कुछ तत्वों

    for(auto f=myType.begin(), l=myType.end(); f!=l; ++f) 
    { 
        if (!doProcessing(*f)) 
         break; 
    } 
    
  • के बाद डाटा प्रोसेसिंग के बंद हो जाता है इस से इनकी हो सकता है भले ही उपभोक्ता अंततः 0 तत्वों को संसाधित करता है: बी नहीं हो सकता है ई किसी भी विशेष पल में सभी तत्वों की प्रतिलिपि बनाने की आवश्यकता है, इसलिए 'वर्तमान तत्व' के लिए 'स्लॉट' का पुन: उपयोग किया जा सकता है, स्मृति आवश्यकताओं को कम करने, कैश इलाके में वृद्धि। जैसे:

    std::vector<myElementType> v(myType.begin(), myType.end()); 
    
    // look: the client gets to _decide_ what container he wants! 
    std::set<myElementType, myComparer> s(myType.begin(), myType.end()); 
    

    इस लचीलेपन अन्यथा हो रही का प्रयास करें:

    for(auto f=myType.begin(), l=myType.end(); f!=l; ++f) 
    { 
        myElementType const& slot = *f; // making the temp explicit 
        doProcessing(slot); 
    } 
    

ध्यान दें कि इटरेटर इंटरफेस बस अभी भी बेहतर है, तो उपभोक्ता एक संग्रह सभी तत्वों वाली चाहता था कर रहे हैं।

अंत में

, शैली के कुछ तत्वों को देखते हैं:

  • स्वभाव से यह (स्थिरांक) iterators का उपयोग कर तत्वों के लिए संदर्भ का पर्दाफाश करने के लिए आसान है, इससे ऑब्जेक्ट स्लाइसिंग से बचने के लिए और ग्राहकों को polymorphically तत्वों का उपयोग करने में सक्षम बनाता है।

  • पुनरावृत्ति पर गैर-कॉन्स्ट संदर्भों को वापस करने के लिए इटरेटर-शैली इंटरफेस को ओवरलोड किया जा सकता है। एक कंटेनर वापस करने, संदर्भ हो सकता है नहीं (सीधे)

  • अगर आप की सीमा के आधार पर के लिए सी ++ 11 में आप कुछ वाक्यात्मक चीनी हो सकता है आवश्यकताओं का पालन:

    for (auto& slot : myType) 
    { 
        doProcessing(slot); 
    } 
    

अंत में, (ऊपर दिखाया गया है), सामान्य अर्थ में यह मानक पुस्तकालय के साथ अच्छी तरह से काम करता है।


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

2

पहले बात (आप किसी भी तरह बिल्कुल भी उल्लेख नहीं किया है) के बारे में

const CollectionClass& MessageSpy::getMessages() 

नोट & मुझे लगता है कि होगा। यह आपको कॉन्स्ट संदर्भ देता है जिसे संशोधित नहीं किया जा सकता है लेकिन इसे स्वतंत्र रूप से स्वीकार किया जा सकता है।

कोई प्रतिलिपि नहीं, जब तक कि आप वास्तव में कॉपी नहीं करना चाहते हैं।

यदि यह उपयुक्त नहीं है, उदाहरण के लिए, क्यूटी, कक्षाओं के लिए "implicit data sharing" का उपयोग करता है। आईई। आपकी कक्षाएं "kinda" मान द्वारा लौटाई जाती हैं, लेकिन जब तक आप उनमें से किसी एक पर लिखने का प्रयास नहीं करते हैं, तब तक उनका आंतरिक डेटा साझा किया जाता है। इस मामले में, जिस वर्ग में आप लिखने की कोशिश कर रहे हैं, एक गहरी प्रतिलिपि करता है, और डेटा साझा किया जा रहा है। इसका मतलब है कि कम डेटा चारों ओर ले जाया गया है।

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

मैं "iterators" की अनुशंसा नहीं करता, क्योंकि auto कीवर्ड के बिना C++ 03 कंपाइलर पर उनका उपयोग # & @ में शाही दर्द है। लंबे नाम या कई typedefs। मैं इसके बजाय कंटेनर के संदर्भ में कॉन्स संदर्भ वापस कर दूंगा।

+0

+1 – sehe

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