जैसा कि @ JDługosz टिप्पणियों में बताते हैं, हर्ब दूसरे में (बाद में?) बात करने की सलाह देता है, यहाँ से मोटे तौर पर देखें: https://youtu.be/xnqTKD8uD64?t=54m50s ।
उनकी सलाह केवल एक फ़ंक्शन के लिए मान मापदंडों का उपयोग करके उबलती है fजो तथाकथित सिंक तर्क लेती है, यह मानते हुए कि आप इन सिंक नियुक्तियों से निर्माण करेंगे।
यह सामान्य दृष्टिकोण fक्रमशः लैवल्यू और रिवेल्यू तर्कों के अनुरूप कार्यान्वयन की तुलना में केवल लेवल्यू और रिवेल्यू तर्क दोनों के लिए एक कदम निर्माणकर्ता के ओवरहेड को जोड़ता है। यह देखने के लिए कि ऐसा क्यों है, मान लीजिए कि fएक मान पैरामीटर है, जहां Tकुछ प्रतिलिपि और रचनात्मक प्रकार स्थानांतरित होते हैं:
void f(T x) {
T y{std::move(x)};
}
fएक लैवल्यू तर्क के साथ कॉल करने के परिणामस्वरूप एक कॉपी कंस्ट्रक्टर को निर्माण के लिए बुलाया जाएगा x, और एक निर्माण कंस्ट्रक्टर को निर्माण के लिए बुलाया जाएगा y। दूसरी ओर, fएक प्रतिद्वंद्विता के तर्क के साथ कॉल करने से एक निर्माण करने वाले को निर्माण करने के लिए बुलाया जाएगा x, और एक अन्य चाल निर्माणकर्ता को निर्माण के लिए बुलाया जाएगा y।
सामान्य तौर पर, flvalue तर्कों के लिए इष्टतम कार्यान्वयन निम्नानुसार है:
void f(const T& x) {
T y{x};
}
इस मामले में, केवल एक प्रतिलिपि निर्माता को निर्माण करने के लिए कहा जाता है y। fआम तौर पर फिर से, तर्क तर्कों के लिए इष्टतम कार्यान्वयन है:
void f(T&& x) {
T y{std::move(x)};
}
इस मामले में, केवल एक चाल निर्माणकर्ता को निर्माण करने के लिए कहा जाता है y।
इसलिए एक समझदार समझौता एक मूल्य पैरामीटर लेना है और इष्टतम कार्यान्वयन के संबंध में या तो अंतराल या तर्क तर्कों के लिए एक अतिरिक्त चाल निर्माता कॉल है, जो हर्ब की बात में दी गई सलाह भी है।
जैसा कि @ JDługosz ने टिप्पणियों में बताया है, मूल्य से गुजरना केवल उन कार्यों के लिए समझ में आता है जो सिंक तर्क से कुछ ऑब्जेक्ट का निर्माण करेंगे। जब आपके पास एक फ़ंक्शन होता है fजो इसके तर्क की प्रतिलिपि बनाता है, तो पास-दर-मूल्य दृष्टिकोण सामान्य पास-बाय-कॉन्स्ट-रेफ़रेंस दृष्टिकोण की तुलना में अधिक ओवरहेड होगा। किसी फ़ंक्शन के लिए पास-दर-मूल्य दृष्टिकोण fजो उसके पैरामीटर की एक प्रति को बरकरार रखता है, उसके पास फ़ॉर्म होगा:
void f(T x) {
T y{...};
...
y = std::move(x);
}
इस मामले में, एक प्रतिवाद तर्क के लिए एक प्रतिलिपि निर्माण और एक चाल असाइनमेंट है, और एक चाल निर्माण और एक तर्क तर्क के लिए चाल असाइनमेंट है। एक तर्क तर्क के लिए सबसे इष्टतम मामला है:
void f(const T& x) {
T y{...};
...
y = x;
}
यह केवल एक असाइनमेंट के लिए उबालता है, जो पास-पास-मूल्य दृष्टिकोण के लिए आवश्यक कॉपी कंस्ट्रक्टर प्लस मूव असाइनमेंट की तुलना में बहुत सस्ता है। इसका कारण यह है कि असाइनमेंट मौजूदा आवंटित मेमोरी का पुन: उपयोग कर सकता हैy , और इसलिए (डी) आवंटन को रोक सकता है, जबकि कॉपी कंस्ट्रक्टर आमतौर पर मेमोरी आवंटित करेगा।
एक तर्क तर्क के लिए fकि प्रतिलिपि बनाए रखने के लिए सबसे इष्टतम कार्यान्वयन का रूप है:
void f(T&& x) {
T y{...};
...
y = std::move(x);
}
तो, इस मामले में केवल एक चाल असाइनमेंट। उस संस्करण के लिए एक अंतराल पारित करना एक कॉन्स्टिट्यूशन fलेता है केवल एक चाल असाइनमेंट के बजाय एक असाइनमेंट खर्च होता है। इतना अपेक्षाकृत, का संस्करणf सामान्य बात है कि सामान्य कार्यान्वयन के रूप में इस मामले में एक कास्ट संदर्भ लेने बेहतर है।
तो सामान्य तौर पर, सबसे इष्टतम कार्यान्वयन के लिए, आपको ओवरलोड करने या किसी प्रकार की सही अग्रेषण करने की आवश्यकता होगी जैसा कि बात में दिखाया गया है। दोष आपके लिए आवश्यक अधिभार की संख्या में एक दहनशील विस्फोट है, इस बात के लिए मापदंडों की संख्या के आधार पर कि fआप तर्क के मूल्य वर्ग पर अधिभार का विकल्प चुनते हैं। परफेक्ट फ़ॉरवर्डिंग में एक खामी है जो fएक टेम्प्लेट फ़ंक्शन बन जाता है, जो इसे आभासी बनाने से रोकता है, और यदि आप इसे 100% सही प्राप्त करना चाहते हैं, तो (अधिक विवरण कोड देखें)