टीएल; डीआर: कॉन्स्ट रेफरेंस द्वारा पास सी ++ में अभी भी एक अच्छा विचार है, सभी चीजों पर विचार किया गया है। समयपूर्व अनुकूलन नहीं।
TL; DR2: अधिकांश कहावतें समझ में नहीं आतीं, जब तक कि वे ऐसा न करें।
लक्ष्य
यह उत्तर केवल सी ++ कोर दिशानिर्देश (पहले अमोन की टिप्पणी में उल्लिखित) पर लिंक किए गए आइटम को थोड़ा सा विस्तारित करने की कोशिश करता है ।
यह उत्तर इस बात के मुद्दे को संबोधित करने का प्रयास नहीं करता है कि प्रोग्रामर के हलकों में व्यापक रूप से प्रसारित किए गए विभिन्न विज्ञापनों को कैसे सोचना और लागू करना है, विशेष रूप से परस्पर विरोधी निष्कर्षों या सबूतों के बीच सामंजस्य स्थापित करने का मुद्दा।
प्रयोज्यता
यह उत्तर केवल फ़ंक्शन कॉल (एक ही थ्रेड पर गैर-वियोज्य नेस्टेड स्कोप) पर लागू होता है।
(साइड नोट।) जब पास होने योग्य चीजें गुंजाइश से बच सकती हैं (यानी एक जीवनकाल है जो संभावित रूप से बाहरी दायरे से अधिक है), तो किसी भी चीज से पहले ऑब्जेक्ट लाइफटाइम प्रबंधन के लिए आवेदन की आवश्यकता को पूरा करना अधिक महत्वपूर्ण हो जाता है। आमतौर पर, यह उन संदर्भों का उपयोग करने की आवश्यकता होती है जो जीवन भर के प्रबंधन में सक्षम होते हैं, जैसे कि स्मार्ट पॉइंटर्स। एक प्रबंधक एक विकल्प का उपयोग कर सकता है। ध्यान दें, लैंबडा एक प्रकार का वियोज्य गुंजाइश है; लैम्ब्डा कैप्चर ऑब्जेक्ट स्कोप होने की तरह व्यवहार करता है। इसलिए, लैम्ब्डा कैप्चर से सावधान रहें। इसके अलावा सावधान रहें कि लैम्ब्डा खुद कैसे पारित होता है - कॉपी या संदर्भ द्वारा।
जब मूल्य से गुजरना है
उन मानों के लिए जो अदिश (मानक आदिम हैं जो एक मशीन रजिस्टर के भीतर फिट होते हैं और वैल्यू सिमेंटिक होते हैं) जिनके लिए संचार-बाय-म्यूटेबिलिटी (साझा संदर्भ) की आवश्यकता नहीं है, मान से पास करें।
उन स्थितियों के लिए जहां कैली को किसी ऑब्जेक्ट या एग्रीगेट के क्लोनिंग की आवश्यकता होती है, मूल्य से गुजरती हैं, जिसमें कैली की कॉपी एक क्लोन ऑब्जेक्ट की आवश्यकता को पूरा करती है।
कब संदर्भ से गुजरना है, आदि।
अन्य सभी स्थितियों के लिए, पॉइंटर्स, रेफरेंस, स्मार्ट पॉइंटर्स, हैंडल (देखें: हैंडल-बॉडी मुहावरा), इत्यादि से गुजरें। जब भी इस सलाह का पालन किया जाए, तो हमेशा की तरह कॉन्स्टीट्यूशन के सिद्धांत को लागू करें।
ऐसी चीजें (एग्रीगेट, ऑब्जेक्ट्स, एरेज़, डेटा स्ट्रक्चर्स) जो मेमोरी फुटप्रिंट में पर्याप्त रूप से बड़ी हैं, उन्हें हमेशा प्रदर्शन कारणों के लिए पास-बाय-संदर्भ की सुविधा के लिए डिज़ाइन किया जाना चाहिए। यह सलाह निश्चित रूप से तब लागू होती है जब यह सैकड़ों बाइट्स या अधिक हो। यह सलाह सीमा रेखा है जब यह दसियों बाइट्स है।
असामान्य प्रतिमान
विशेष प्रयोजन के प्रोग्रामिंग प्रतिमान हैं जो इरादे से प्रतिलिपि-भारी हैं। उदाहरण के लिए, स्ट्रिंग प्रोसेसिंग, सीरियललाइज़ेशन, नेटवर्क कम्युनिकेशन, आइसोलेशन, थर्ड-पार्टी लाइब्रेरीज़ की रैपिंग, शेयर-मेमोरी इंटर-प्रोसेस कम्युनिकेशन, आदि। इन एप्लिकेशन क्षेत्रों या प्रोग्रामिंग प्रतिमानों में, डेटा को स्ट्रक्चर्स से स्ट्रक्चर्स में कॉपी किया जाता है, या कभी-कभी इसमें अप्रभावित किया जाता है। बाइट सरण।
अनुकूलन पर विचार करने से पहले भाषा विनिर्देश इस उत्तर को कैसे प्रभावित करता है।
उप-टीएल; डीआर एक संदर्भ को प्रचारित करने के लिए कोई कोड नहीं लाना चाहिए; कॉन्स्ट-रेफरेंस से गुजरना इस कसौटी पर खरा उतरता है। हालाँकि, अन्य सभी भाषाएँ इस कसौटी को सहजता से पूरा करती हैं।
(Novice C ++ प्रोग्रामर को सलाह दी जाती है कि वे इस सेक्शन को पूरी तरह से छोड़ दें।)
(इस खंड की शुरुआत आंशिक रूप से gnasher729 के उत्तर से प्रेरित है। हालांकि, एक अलग निष्कर्ष पर पहुंच गया है।)
C ++ उपयोगकर्ता-परिभाषित कॉपी कंस्ट्रक्टर और असाइनमेंट ऑपरेटर की अनुमति देता है।
(यह एक बोल्ड चॉइस है जो कि (और) दोनों अद्भुत और शोचनीय है। यह निश्चित रूप से भाषा डिजाइन में आज के स्वीकार्य मानदंड से भिन्न है।)
यहां तक कि अगर C ++ प्रोग्रामर एक को परिभाषित नहीं करता है, तो C ++ कंपाइलर को भाषा के सिद्धांतों के आधार पर इस तरह के तरीके उत्पन्न करने होंगे, और फिर यह निर्धारित करना होगा कि क्या अतिरिक्त कोड को इसके अलावा निष्पादित करने की आवश्यकता है memcpy
। उदाहरण के लिए, एक class
/ struct
जिसमें एक std::vector
सदस्य होता है उसके पास कॉपी-कंस्ट्रक्टर और असाइनमेंट ऑपरेटर होता है जो गैर-तुच्छ होता है।
अन्य भाषाओं में, कॉपी कंस्ट्रक्टर और ऑब्जेक्ट क्लोनिंग को हतोत्साहित किया जाता है (जहां आवेदन के शब्दार्थ के लिए बिल्कुल आवश्यक और / या सार्थक को छोड़कर), क्योंकि ऑब्जेक्ट में भाषा डिजाइन द्वारा संदर्भ शब्दार्थ हैं। इन भाषाओं में आमतौर पर कचरा संग्रह तंत्र होगा जो कि स्कोप-आधारित स्वामित्व या संदर्भ-गिनती के बजाय पुनःचुन्यता पर आधारित होता है।
जब कोई संदर्भ या पॉइंटर (कॉन्स्ट रेफरेंस सहित) C ++ (या C) में इधर से उधर हो जाता है, तो प्रोग्रामर को आश्वासन दिया जाता है कि कोई विशेष कोड (उपयोगकर्ता द्वारा परिभाषित या संकलित-जनित कार्य) निष्पादित नहीं किया जाएगा, जो एड्रेस वैल्यू के प्रसार के अलावा है। (संदर्भ या सूचक)। यह व्यवहार की एक स्पष्टता है जो C ++ प्रोग्रामर के साथ सहज है।
हालांकि, पृष्ठभूमि यह है कि सी ++ भाषा अनावश्यक रूप से जटिल है, जैसे कि व्यवहार की यह स्पष्टता एक परमाणु पतन क्षेत्र के आसपास कहीं न कहीं एक नखलिस्तान (एक जीवित निवास स्थान) की तरह है।
अधिक आशीर्वाद (या अपमान) को जोड़ने के लिए, C ++ उपयोगकर्ता द्वारा परिभाषित चाल ऑपरेटरों (चाल-निर्माण और चाल-असाइनमेंट ऑपरेटरों) को अच्छे प्रदर्शन के साथ सुविधा प्रदान करने के लिए सार्वभौमिक संदर्भ (आर-मान) का परिचय देता है। यह नकल और गहरी-क्लोनिंग की आवश्यकता को कम करने के माध्यम से अत्यधिक प्रासंगिक उपयोग के मामले (एक उदाहरण से दूसरे स्थान पर वस्तुओं का स्थानांतरण) को लाभ पहुंचाता है। हालांकि, अन्य भाषाओं में, वस्तुओं के इस तरह के बढ़ने की बात करना अतार्किक है।
(ऑफ-टॉपिक सेक्शन) एक आर्टिकल को समर्पित एक सेक्शन, "वांट स्पीड! पास बाई वैल्यू!" लगभग 2009 में लिखा था।
यह लेख 2009 में लिखा गया था और सी ++ में आर-मूल्य के लिए डिजाइन औचित्य की व्याख्या करता है। वह लेख पिछले खंड में मेरे निष्कर्ष के लिए एक वैध प्रतिवाद प्रस्तुत करता है। हालांकि, लेख का कोड उदाहरण और प्रदर्शन का दावा लंबे समय से खारिज कर दिया गया है।
उप-टीएल; डॉ । सी + + में आर-मूल्य शब्दार्थ का डिज़ाइन एक Sort
फ़ंक्शन पर आश्चर्यजनक रूप से सुरुचिपूर्ण उपयोगकर्ता-साइड शब्दार्थ के लिए अनुमति देता है , उदाहरण के लिए। यह सुरुचिपूर्ण अन्य भाषाओं में मॉडल (अनुकरण) करना असंभव है।
एक प्रकार का फ़ंक्शन पूरे डेटा संरचना पर लागू होता है। जैसा कि ऊपर उल्लेख किया गया है, यदि बहुत अधिक नकल शामिल है तो यह धीमा होगा। एक प्रदर्शन अनुकूलन (जो व्यावहारिक रूप से प्रासंगिक है) के रूप में, एक प्रकार का फ़ंक्शन C ++ के अलावा काफी कुछ भाषाओं में विनाशकारी होने के लिए डिज़ाइन किया गया है। विनाशकारी का मतलब है कि लक्ष्य डेटा संरचना को सॉर्टिंग लक्ष्य को प्राप्त करने के लिए संशोधित किया गया है।
C ++ में, उपयोगकर्ता दो कार्यान्वयन में से एक को कॉल करने का विकल्प चुन सकता है: बेहतर प्रदर्शन के साथ एक विनाशकारी, या एक सामान्य एक जो इनपुट को संशोधित नहीं करता है। (टेम्पलेट संक्षिप्तता के लिए छोड़ा गया है।)
/*caller specifically passes in input argument destructively*/
std::vector<T> my_sort(std::vector<T>&& input)
{
std::vector<T> result(std::move(input)); /* destructive move */
std::sort(result.begin(), result.end()); /* in-place sorting */
return result; /* return-value optimization (RVO) */
}
/*caller specifically passes in read-only argument*/
std::vector<T> my_sort(const std::vector<T>& input)
{
/* reuse destructive implementation by letting it work on a clone. */
/* Several things involved; e.g. expiring temporaries as r-value */
/* return-value optimization, etc. */
return my_sort(std::vector<T>(input));
}
/*caller can select which to call, by selecting r-value*/
std::vector<T> v1 = {...};
std::vector<T> v2 = my_sort(v1); /*non-destructive*/
std::vector<T> v3 = my_sort(std::move(v1)); /*v1 is gutted*/
छांटने के अलावा, यह लालित्य पुनरावर्ती विभाजन द्वारा एक सरणी (आरंभ में अनसोल्ड) में विनाशकारी मध्ययुगीन खोज एल्गोरिथ्म के कार्यान्वयन में भी उपयोगी है।
हालाँकि, ध्यान दें कि, अधिकांश भाषाएं बाइनरी एसेन्श ट्री ट्री एप्रोच को सॉर्ट करने के लिए लागू करेंगी, बजाए एक डिस्ट्रक्टिव छँटाई एल्गोरिथम लागू करने के। इसलिए, इस तकनीक की व्यावहारिक प्रासंगिकता उतनी अधिक नहीं है जितनी लगती है।
कंपाइलर ऑप्टिमाइज़ेशन इस उत्तर को कैसे प्रभावित करता है
जब इनलाइनिंग (और पूरे-प्रोग्राम ऑप्टिमाइज़ेशन / लिंक-टाइम ऑप्टिमाइज़ेशन) को फ़ंक्शन कॉल के कई स्तरों पर लागू किया जाता है, तो कंपाइलर डेटा के प्रवाह को कभी-कभी देखने में सक्षम होता है। जब ऐसा होता है, तो कंपाइलर कई अनुकूलन लागू कर सकता है, जिनमें से कुछ मेमोरी में संपूर्ण वस्तुओं के निर्माण को समाप्त कर सकते हैं। आमतौर पर, जब यह स्थिति लागू होती है, तो यह मायने नहीं रखता है कि पैरामीटर मान या कॉन्स्टेंस-रेफ़रेंस द्वारा पारित किए गए हैं, क्योंकि कंपाइलर संपूर्ण विश्लेषण कर सकता है।
हालांकि, अगर निचले स्तर का कार्य कुछ ऐसा है जो विश्लेषण से परे है (जैसे संकलन के बाहर एक अलग पुस्तकालय में कुछ, या कॉल ग्राफ़ जो बहुत जटिल है), तो संकलक को रक्षात्मक रूप से अनुकूलित करना होगा।
मशीन रजिस्टर मूल्य से बड़ी वस्तुओं को स्पष्ट मेमोरी लोड / स्टोर निर्देशों द्वारा या आदरणीय memcpy
फ़ंक्शन को कॉल करके कॉपी किया जा सकता है । कुछ प्लेटफार्मों पर, कंपाइलर दो मेमोरी स्थानों के बीच स्थानांतरित करने के लिए SIMD निर्देश उत्पन्न करता है, प्रत्येक निर्देश दसियों बाइट्स (16 या 32) को स्थानांतरित करता है।
वाचालता या दृश्य अव्यवस्था के मुद्दे पर चर्चा
C ++ प्रोग्रामर इसके आदी हैं, जब तक कि प्रोग्रामर C ++ से नफरत नहीं करता है, सोर्स कोड में कॉन्स्ट-रेफरेंस लिखने या पढ़ने का ओवरहेड भयानक नहीं है।
लागत-लाभ विश्लेषण पहले कई बार किया जा सकता है। मुझे नहीं पता कि क्या कोई वैज्ञानिक है जिसे उद्धृत किया जाना चाहिए। मुझे लगता है कि अधिकांश विश्लेषण गैर-वैज्ञानिक या गैर-प्रजनन योग्य होंगे।
यहाँ मैं कल्पना करता हूं (बिना प्रमाण या विश्वसनीय संदर्भ के) ...
- हां, यह इस भाषा में लिखे सॉफ्टवेयर के प्रदर्शन को प्रभावित करता है।
- यदि संकलक कोड के उद्देश्य को समझ सकते हैं, तो संभवतः इसे स्वचालित करने के लिए पर्याप्त स्मार्ट हो सकता है
- दुर्भाग्य से, ऐसी भाषाओं में, जो म्यूटेबिलिटी (कार्यात्मक शुद्धता के विपरीत) के पक्ष में हैं, संकलक म्यूट किए जाने के रूप में अधिकांश चीजों को वर्गीकृत करेगा, इसलिए कब्ज की स्वचालित कटौती गैर-कास्ट के रूप में अधिकांश चीजों को अस्वीकार कर देगी।
- मानसिक ओवरहेड लोगों पर निर्भर करता है; जो लोग इसे एक उच्च मानसिक ओवरहेड पाते हैं वे व्यवहार्य प्रोग्रामिंग भाषा के रूप में C ++ को अस्वीकार कर देते थे।