C++ में किसी फ़ंक्शन से मान लौटाते समय, हमारे पास कॉपी एलीशन और (नामांकित) रिटर्न वैल्यू ऑप्टिमाइज़ेशन होता है जो हमें अधिक कुशल कोड बनाने में मदद करता है। संक्षेप में, निम्नलिखित कोड:

std::vector<int> make_vec_1(){
    std::vector<int> v;
    v.resize(1e6);
    return v;
}

एक प्रति के बजाय, वापसी मूल्य के गंतव्य में एक मूक चाल या प्रत्यक्ष निर्माण में परिणाम। इसके आस-पास के नियमों का यह भी अर्थ है कि लौटने पर लौटाई गई वस्तु को स्पष्ट रूप से ले जाना वास्तव में इन अनुकूलन को रोकता है।

std::vector<int> make_vec_2(){
    std::vector<int> v;
    v.resize(1e6);
    return std::move(v); // BAD
}

यह संस्करण आरवीओ को रोकता है, जैसा कि स्कॉट मेयर्स के प्रभावी आधुनिक सी++, आइटम 25 में बताया गया है।


मेरा सवाल यह है कि क्या होता है जब रिटर्न प्रकार अलग होता है, लेकिन एक या अधिक स्थानीय चर से स्थानांतरित किया जा सकता है? निम्नलिखित कार्यों पर विचार करें जो प्रत्येक एक वैकल्पिक वेक्टर लौटाते हैं:

std::optional<std::vector<int>> make_opt_vec_1(){
    std::vector<int> v;
    v.resize(1e6);
    return v; // no move
}

std::optional<std::vector<int>> make_opt_vec_2(){
    std::vector<int> v;
    v.resize(1e6);
    return std::move(v); // move
}

इनमें से कौन सही है? लाइन return std::move(v) मुझे पहली बार में लाल झंडे की तरह दिखती है, लेकिन मुझे यह भी संदेह है कि यह यहां करने के लिए सही काम है। वही निम्नलिखित दो कार्यों के लिए जाता है जो वैक्टर की एक जोड़ी लौटाते हैं:

std::pair<std::vector<int>, std::vector<int>> make_vec_pair_1(){
    std::vector<int> v1, v2;
    v1.resize(1e6);
    v2.resize(1e6);
    return {v1, v2}; // no move
}

std::pair<std::vector<int>, std::vector<int>> make_vec_pair_2(){
    std::vector<int> v1, v2;
    v1.resize(1e6);
    v2.resize(1e6);
    return {std::move(v1), std::move(v2)}; // move
}

इस मामले में भी, पहली नज़र में अजीब लगने के बावजूद, मुझे लगता है कि रिटर्न वैल्यू में जाना बेहतर है।

क्या मैं सही हूं कि प्रकार भिन्न होने पर वापसी मूल्य में जाना बेहतर होता है, लेकिन वापसी मूल्य को स्थानीय चर (ओं) से स्थानांतरित किया जा सकता है? क्या मैंने एनआरवीओ को गलत समझा है, या कोई अन्य अनुकूलन है जो यहां मुझसे काफी आगे है?

7
alter igel 6 जून 2019, 22:42

1 उत्तर

सबसे बढ़िया उत्तर

क्या मैं सही हूं कि प्रकार भिन्न होने पर वापसी मूल्य में जाना बेहतर होता है, लेकिन वापसी मूल्य को स्थानीय चर (ओं) से स्थानांतरित किया जा सकता है? क्या मैंने एनआरवीओ को गलत समझा है, या कोई अन्य अनुकूलन है जो यहां मुझसे काफी आगे है?

आप एक बात से चूक गए। भले ही प्रकार भिन्न हों, एक अंतर्निहित चाल स्वचालित रूप से की जाएगी।

[class.copy.elision] (जोर मेरा)

3 निम्नलिखित कॉपी-आरंभीकरण संदर्भों में, एक चाल कार्यवाही कॉपी ऑपरेशन के बजाय इस्तेमाल किया जा सकता है:

  • यदि रिटर्न स्टेटमेंट में एक्सप्रेशन एक (संभवतः कोष्ठक में दिया गया) आईडी-एक्सप्रेशन है जो किसी ऑब्जेक्ट को ऑटोमेटिक नाम देता है शरीर या पैरामीटर-घोषणा-खंड में घोषित भंडारण अवधि अंतरतम संलग्न कार्य या लैम्ब्डा-अभिव्यक्ति, या

  • यदि थ्रो-एक्सप्रेशन का ऑपरेंड एक गैर-वाष्पशील स्वचालित ऑब्जेक्ट का नाम है (फ़ंक्शन या कैच-क्लॉज़ पैरामीटर के अलावा) जिसका दायरा अंतरतम परिक्षेत्र के अंत से आगे नहीं बढ़ता है ट्राई-ब्लॉक (यदि कोई हो तो),

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

यह मेल खाने वाले प्रकारों पर निर्भर नहीं है, और यदि पूर्ण (एन) आरवीओ नहीं होता है तो यह एक फॉलबैक व्यवहार है। इसलिए आप स्पष्ट रूप से make_opt_vec_2 में जाने से कुछ हासिल नहीं करते हैं।

यह देखते हुए कि std::move या तो निराशावाद है या पूरी तरह से अनावश्यक है, मैं तर्क दूंगा कि किसी फ़ंक्शन स्थानीय ऑब्जेक्ट को वापस करते समय इसे करना सबसे अच्छा नहीं है।

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

यहां अंगूठे का नियम केवल एक आईडी-अभिव्यक्ति को स्थानांतरित नहीं करना है जो एक फ़ंक्शन स्थानीय वस्तु है। नहीं तो हट जाओ।

9
StoryTeller - Unslander Monica 6 जून 2019, 20:08