क्या सी या सी ++ में एक संरचना वापस करना सुरक्षित है?


85

जो मैं समझता हूं कि यह नहीं किया जाना चाहिए, लेकिन मेरा मानना ​​है कि मैंने ऐसे उदाहरण देखे हैं जो कुछ ऐसा करते हैं (नोट कोड जरूरी नहीं कि वाक्यविन्यास सही हो लेकिन विचार वहां है)

typedef struct{
    int a,b;
}mystruct;

और फिर यहाँ एक समारोह है

mystruct func(int c, int d){
    mystruct retval;
    retval.a = c;
    retval.b = d;
    return retval;
}

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

आइए प्रश्न में दूसरा भाग जोड़ें: क्या यह संकलक द्वारा भिन्न होता है? यदि यह करता है, तो डेस्कटॉप के लिए संकलक के नवीनतम संस्करणों के लिए व्यवहार क्या है: gcc, g ++ और Visual Studio?

बात पर विचार?


34
"मैं जो समझता हूं कि यह नहीं होना चाहिए" कौन कहता है? मैं इसे हर समय कर रहा हूं। यह भी ध्यान दें कि टाइप ++ को C ++ में आवश्यक नहीं है, और यह कि "C / C ++" जैसी कोई चीज मौजूद नहीं है।
प्लाज़्मा एचएच

4
प्रश्न सी + + पर लक्षित नहीं किया गया लगता है ।
कप्तान जिराफ

4
@PlasmaHH आसपास बड़ी संरचनाओं को कॉपी करना अक्षम्य हो सकता है। इसलिए किसी को सावधान रहना चाहिए और मूल्य द्वारा संरचना को वापस करने से पहले सोचना चाहिए, खासकर अगर संरचना में एक महंगा कॉपी कंस्ट्रक्टर है और कंपाइलर रिटर्न वैल्यू ऑप्टिमाइजेशन में अच्छा नहीं है। मैंने हाल ही में एक ऐप के लिए एक अनुकूलन किया जो कुछ बड़े संरचनाओं के लिए कॉपी कंस्ट्रक्टर्स में अपने समय का एक महत्वपूर्ण हिस्सा खर्च कर रहा था जिसे एक प्रोग्रामर ने हर जगह मूल्य द्वारा वापस करने का फैसला किया था। अक्षमता हमें $ 800,000 के बारे में खर्च कर रही थी अतिरिक्त डेटासेंटर हार्डवेयर में हमें खरीदने की आवश्यकता थी।
क्रैश

8
@ क्रशवर्क: बधाई हो, मुझे आशा है कि आपके बॉस ने आपको एक वृद्धि दी है।
प्लाज़्मा एचएच

6
@Crashworks: सुनिश्चित करें कि बिना सोचे-समझे हमेशा वैल्यू करके लौटना बुरा है , लेकिन ऐसी स्थितियों में जहां यह स्वाभाविक बात है कि आमतौर पर कोई सुरक्षित विकल्प नहीं है, जिसे कॉपी करने की भी आवश्यकता नहीं होती है, इसलिए वैल्यू के हिसाब से रिटर्न करना सबसे अच्छा उपाय है। किसी भी ढेर आवंटन की जरूरत नहीं है। अक्सर भी नहीं होगा होना , एक प्रति एक अच्छा संकलक प्रतिलिपि इलिजन का उपयोग करते समय यह संभव है में और सी ++ 11 में कूद चाहिए, चाल अर्थ विज्ञान गहरे कॉपी करने की और भी समाप्त कर सकते हैं। यदि आप कुछ और करते हैं, लेकिन मूल्य से वापस आते हैं तो दोनों तंत्र ठीक से काम नहीं करेंगे ।
२०:

जवाबों:


78

यह पूरी तरह से सुरक्षित है, और ऐसा करना गलत नहीं है। यह भी: यह संकलक द्वारा भिन्न नहीं होता है।

आमतौर पर, जब (आपके उदाहरण की तरह) आपकी संरचना बहुत बड़ी नहीं होती है, तो मैं यह तर्क दूंगा कि यह दृष्टिकोण एक मॉलॉक संरचना ( mallocएक महंगा ऑपरेशन है) की तुलना में बेहतर है ।


3
क्या यह अभी भी सुरक्षित होगा यदि खेतों में से एक चार * था? अब संरचना में सूचक होगा
jzepeda

3
@ user963258 वास्तव में, यह इस बात पर निर्भर करता है कि आप कॉपी कंस्ट्रक्टर और डिस्ट्रक्टर को कैसे लागू करते हैं।
लुचियन ग्रिगोर

2
@PabloSantaCruz यह एक मुश्किल सवाल है। यदि यह एक परीक्षा का प्रश्न था, तो परीक्षार्थी एक प्रतिक्रिया के रूप में "नहीं" की उम्मीद कर सकता है, अगर स्वामित्व पर विचार करने की आवश्यकता है।
कप्तान जिराफ

2
@CaptainGiraffe: सच है। चूंकि ओपी ने इसे स्पष्ट नहीं किया था, और उनके उदाहरण मूल रूप से C थे , इसलिए मैंने माना कि यह C ++ से अधिक C प्रश्न था ।
पाब्लो सांता क्रूज़

2
@ कुछ संकलनों में NRVO नहीं है? किस साल से? यह भी ध्यान दें: C ++ 11 में भले ही इसमें NRVO न हो, लेकिन यह बदले हुए शब्दार्थ को लागू करेगा।
डेविड

73

यह पूरी तरह से सुरक्षित है।

आप मान से लौट रहे हैं। यदि आप संदर्भ द्वारा लौट रहे हैं तो अपरिभाषित व्यवहार के लिए क्या होगा।

//safe
mystruct func(int c, int d){
    mystruct retval;
    retval.a = c;
    retval.b = d;
    return retval;
}

//undefined behavior
mystruct& func(int c, int d){
    mystruct retval;
    retval.a = c;
    retval.b = d;
    return retval;
}

आपके स्निपेट का व्यवहार पूरी तरह से मान्य और परिभाषित है। यह संकलक द्वारा भिन्न नहीं होता है। यह ठीक है!

व्यक्तिगत रूप से मैं हमेशा पॉलीकोल को एक मॉलोकड संरचना में लौटाता हूं

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

या केवल फ़ंक्शन के संदर्भ में एक पास करते हैं और वहां मूल्यों को संशोधित करते हैं।

यह विकल्प पूरी तरह से वैध है। यह पसंद की बात है। सामान्य तौर पर, आप ऐसा करते हैं यदि आप मूल संरचना को संशोधित करते हुए फ़ंक्शन से कुछ और वापस करना चाहते हैं।

क्योंकि मेरी समझ यह है कि एक बार फ़ंक्शन का दायरा खत्म हो जाने के बाद, संरचना को आवंटित करने के लिए जो भी स्टैक इस्तेमाल किया गया था, उसे ओवरराइट किया जा सकता है

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


3
आरवीओ का उल्लेख करने के लिए +1। यह महत्वपूर्ण अनुकूलन वास्तव में एसटीएल कंटेनरों की तरह महंगी कॉपी कंस्ट्रक्टर वाली वस्तुओं के लिए इस पैटर्न को संभव बनाता है।
कोस

1
यह ध्यान देने योग्य है कि हालांकि कंपाइलर रिटर्न वैल्यू ऑप्टिमाइज़ेशन करने के लिए स्वतंत्र है, इसकी कोई गारंटी नहीं है। यह कोई ऐसी चीज नहीं है जिस पर आप भरोसा कर सकते हैं, केवल आशा है।
वाटकॉम

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

10

mystructआपके फ़ंक्शन में ऑब्जेक्ट का जीवनकाल वास्तव में समाप्त होता है जब आप फ़ंक्शन छोड़ते हैं। हालाँकि, आप रिटर्न स्टेटमेंट में ऑब्जेक्ट को मान से पास कर रहे हैं। इसका मतलब यह है कि ऑब्जेक्ट को फ़ंक्शन से कॉलिंग फ़ंक्शन में कॉपी किया जाता है। मूल ऑब्जेक्ट चला गया है, लेकिन कॉपी पर रहता है।


9

न केवल structC (या classC ++ में, जहां struct-s वास्तव classमें डिफ़ॉल्ट public:सदस्यों के साथ हैं) में वापस लौटना सुरक्षित है , लेकिन बहुत सा सॉफ्टवेयर ऐसा कर रहा है।

बेशक, classC ++ में लौटने पर , भाषा निर्दिष्ट करती है कि कुछ विध्वंसक या गतिमान निर्माणकर्ता कहा जाएगा, लेकिन ऐसे कई मामले हैं जहां इसे संकलक द्वारा अनुकूलित किया जा सकता है।

इसके अलावा, लिनक्स ABI x86-64 निर्दिष्ट करता है कि एक लौटने structके साथ दो अदिश (जैसे संकेत दिए गए, या long) मान रजिस्टरों (के माध्यम से किया जाता है %raxऔर %rdx) तो बहुत तेज और कुशल है। तो उस विशेष मामले के लिए यह संभव है कि इस तरह के दो-स्केलर फ़ील्ड को वापस करने की structतुलना में कुछ और किया जाए (जैसे कि उन्हें एक संकेतक में तर्क के रूप में संग्रहीत किया जाता है)।

इस तरह के दो-स्केलर फ़ील्ड structको वापस करना तब की तुलना में बहुत तेज़ है mallocऔर एक पॉइंटर लौटाता है।


5

यह पूरी तरह से कानूनी है, लेकिन बड़ी संरचनाओं के साथ दो कारक हैं जिन्हें ध्यान में रखा जाना चाहिए: गति और स्टैक आकार।


1
रिटर्न वैल्यू ऑप्टिमाइज़ेशन के बारे में सुना है?
लुचियन ग्रिगोर

हां, लेकिन हम सामान्य रूप से मूल्य द्वारा वापसी संरचना की बात कर रहे हैं, और ऐसे मामले हैं जहां संकलक आरवीओ प्रदर्शन करने में असमर्थ है।
एबटुसोव

3
मैं कहता हूँ कि कुछ नकल करने के बाद ही आपको अतिरिक्त कॉपी की चिंता होगी।
लुचियन ग्रिगोर

4

एक संरचना प्रकार एक फ़ंक्शन द्वारा लौटाए गए मूल्य के लिए प्रकार हो सकता है। यह सुरक्षित है क्योंकि संकलक संरचना की एक प्रति बनाने जा रहा है और प्रतिलिपि को फ़ंक्शन में स्थानीय संरचना नहीं लौटा रहा है।

typedef struct{
    int a,b;
}mystruct;

mystruct func(int c, int d){
    mystruct retval;
    cout << "func:" <<&retval<< endl;
    retval.a = c;
    retval.b = d;
    return retval;
}

int main()
{
    cout << "main:" <<&(func(1,2))<< endl;


    system("pause");
}

4

सुरक्षा इस बात पर निर्भर करती है कि संरचना को कैसे लागू किया गया था। मैं इस सवाल पर कुछ इसी तरह लागू करते हुए लड़खड़ा गया, और यहाँ संभावित समस्या है।

संकलक, जब मान लौटाता है तो कुछ संचालन करता है (संभवतः दूसरों के बीच):

  1. कॉपी कंस्ट्रक्टर को कॉल करता है mystruct(const mystruct&)( संकलक द्वारा आवंटित फ़ंक्शन के बाहरthis एक अस्थायी चर है)func
  2. ~mystructचर को नष्ट करने वाले को अंदर आवंटित किया गया थाfunc
  3. कॉल mystruct::operator=यदि लौटाया गया मान कुछ और के साथ सौंपा गया है=
  4. ~mystructसंकलक द्वारा उपयोग किए जाने वाले अस्थायी चर पर विध्वंसक को कॉल करता है

अब, अगर mystructयहाँ वर्णित है कि के रूप में सरल रूप में है सब ठीक है, लेकिन अगर यह सूचक (जैसे है char*) या अधिक जटिल स्मृति प्रबंधन, तो यह सब कैसे पर निर्भर करता है mystruct::operator=, mystruct(const mystruct&)और ~mystructलागू किया जाता है। इसलिए, मैं जटिल डेटा संरचनाओं को मूल्य के रूप में वापस करते समय सावधानी बरतने का सुझाव देता हूं।


केवल c ++ 11 से पहले सच।
ब्योर्न सुंडिन

4

आपके द्वारा की गई संरचना को वापस करना पूरी तरह से सुरक्षित है।

हालाँकि इस कथन के आधार पर: क्योंकि मेरी समझ यह है कि एक बार फ़ंक्शन का दायरा समाप्त हो जाने के बाद, संरचना को आवंटित करने के लिए जो भी स्टैक इस्तेमाल किया गया था, उसे ओवरराइट किया जा सकता है, मैं केवल एक परिदृश्य की कल्पना करूँगा जहाँ संरचना के किसी भी सदस्य को गतिशील रूप से आवंटित किया गया था ( Malloc'ed या new'ed), जिस स्थिति में, RVO के बिना, गतिशील रूप से आवंटित सदस्यों को नष्ट कर दिया जाएगा और लौटी हुई प्रतिलिपि में कचरा इंगित करने वाला सदस्य होगा।


स्टैक केवल कॉपी ऑपरेशन के लिए अस्थायी रूप से उपयोग किया जाता है। आमतौर पर, स्टैक कॉल से पहले आरक्षित हो जाता है, और कहा जाता है कि फ़ंक्शन स्टैक पर डेटा वापस करने के लिए डालता है, और फिर कॉलर स्टैक से इस डेटा को खींचता है और इसे स्टोर करता है जहां भी इसे सौंपा जाता है। तो, वहाँ कोई चिंता नहीं है।
थॉमस टेम्पेलमैन

3

मैं sftrabbit के साथ भी सहमत हूँ, जीवन वास्तव में समाप्त हो जाता है और स्टैक क्षेत्र साफ हो जाता है लेकिन कंपाइलर यह सुनिश्चित करने के लिए पर्याप्त स्मार्ट है कि सभी डेटा को रजिस्टरों या किसी तरह से पुनर्प्राप्त किया जाना चाहिए।

पुष्टि के लिए एक सरल उदाहरण नीचे दिया गया है (मिंगव कंपाइलर असेंबली से लिया गया)

_func:
    push    ebp
    mov ebp, esp
    sub esp, 16
    mov eax, DWORD PTR [ebp+8]
    mov DWORD PTR [ebp-8], eax
    mov eax, DWORD PTR [ebp+12]
    mov DWORD PTR [ebp-4], eax
    mov eax, DWORD PTR [ebp-8]
    mov edx, DWORD PTR [ebp-4]
    leave
    ret

आप देख सकते हैं कि edx के माध्यम से b का मान संचारित किया गया है। जबकि डिफ़ॉल्ट ईएक्सएक्स में ए के लिए मूल्य होता है।


2

किसी संरचना को लौटाना सुरक्षित नहीं है। मैं इसे स्वयं करना पसंद करता हूं, लेकिन अगर कोई बाद में दिए गए ढांचे में एक कॉपी कंस्ट्रक्टर जोड़ देगा, तो कॉपी कंस्ट्रक्टर को बुलाया जाएगा। यह अप्रत्याशित हो सकता है और कोड को तोड़ सकता है। इस बग को ढूंढना बहुत मुश्किल है।

मेरे पास अधिक विस्तृत जवाब था, लेकिन मॉडरेटर को यह पसंद नहीं आया। इसलिए, आपके अवसान पर, मेरी टिप छोटी है।


“एक संरचना को वापस करना सुरक्षित नहीं है। […] कॉपी कंस्ट्रक्टर को बुलाया जाएगा। ” - सुरक्षित और अक्षम के बीच अंतर है । एक संरचना लौटना निश्चित रूप से सुरक्षित है। फिर भी, प्रतिलिपि ctor को कॉल करने की संभावना सबसे अधिक संकलक द्वारा दूर की जाएगी क्योंकि इससे शुरू होने के लिए कॉलर के स्टैक पर संरचना बनाई जाती है।
phg

2

आइए प्रश्न में दूसरा भाग जोड़ें: क्या यह संकलक द्वारा भिन्न होता है?

वास्तव में यह ऐसा है, जैसा कि मैंने अपने दर्द का पता लगाया: http://sourceforge.net/p/mingw-w64/mailman/message/33176880/

मैं COM32 को लौटाने वाले इंटरफेस को कॉल करने के लिए win32 (MINGW) पर gcc का उपयोग कर रहा था। यह बताता है कि एमएस इसे GNU से अलग करता है और इसलिए मेरा (gcc) प्रोग्राम एक स्मोक्ड स्टैक के साथ क्रैश हो गया।

यह हो सकता है कि एमएस का उच्च स्तर यहां हो सकता है - लेकिन मुझे परवाह है कि विंडोज पर निर्माण के लिए एमएस और जीएनयू के बीच एबीआई संगतता है।

यदि ऐसा होता है, तो डेस्कटॉप के लिए संकलक के नवीनतम संस्करणों के लिए व्यवहार क्या है: gcc, g ++ और Visual Studio

आप एक शराब मेलिंग सूची पर कुछ संदेश पा सकते हैं कि एमएस ऐसा कैसे करता है।


यदि आप वाइन मेलिंग सूची के लिए एक पॉइंटर देते हैं तो यह अधिक उपयोगी होगा।
जोनाथन लेफ़लर

रिटर्निंग स्ट्रक्चर ठीक है। COM एक बाइनरी इंटरफ़ेस निर्दिष्ट करता है; अगर कोई COM को ठीक से लागू नहीं करता है, तो यह एक बग होगा।
एमएम

1

नोट: यह उत्तर केवल c ++ 11 पर लागू होता है। "सी / सी ++" जैसी कोई चीज नहीं है, वे अलग-अलग भाषाएं हैं।

नहीं, मूल्य द्वारा किसी स्थानीय वस्तु को वापस करने में कोई खतरा नहीं है, और ऐसा करने के लिए सिफारिश की जाती है। हालांकि, मुझे लगता है कि एक महत्वपूर्ण बिंदु है जो यहां सभी उत्तरों से गायब है। कई अन्य लोगों ने कहा है कि संरचना को या तो कॉपी किया जा रहा है या सीधे आरवीओ का उपयोग करके रखा गया है। हालाँकि, यह पूरी तरह सही नहीं है। मैं यह समझाने की कोशिश करूंगा कि स्थानीय वस्तु वापस करते समय कौन सी चीजें हो सकती हैं।

शब्दार्थ को स्थानांतरित करें

सी ++ 11 के बाद से, हमारे पास संदर्भ संदर्भ हैं जो अस्थायी वस्तुओं के संदर्भ हैं जो सुरक्षित रूप से चोरी हो सकते हैं। एक उदाहरण के रूप में, std :: वेक्टर में एक मूव कंस्ट्रक्टर है और साथ ही एक मूव असाइनमेंट ऑपरेटर भी है। इन दोनों में निरंतर जटिलता होती है और बस पॉइंटर को वेक्टर के डेटा से कॉपी किया जाता है। मैं यहाँ कदम शब्दार्थ के बारे में अधिक विस्तार में नहीं जाऊँगा।

क्योंकि किसी फ़ंक्शन के भीतर स्थानीय रूप से बनाई गई वस्तु अस्थायी होती है और फ़ंक्शन के वापस आने पर स्कोप से बाहर चली जाती है, लौटी हुई वस्तु को कभी भी c ++ 11 के साथ कॉपी नहीं किया जाता है। इस कदम के निर्माता को लौटाए जा रहे ऑब्जेक्ट (या बाद में समझाया गया) पर बुलाया जा रहा है। इसका मतलब यह है कि यदि आप किसी ऑब्जेक्ट को एक महंगी कॉपी कंस्ट्रक्टर के साथ लेकिन सस्ती चाल वाले कंस्ट्रक्टर के साथ वापस करना चाहते थे, तो एक बड़े वेक्टर की तरह, केवल डेटा का स्वामित्व स्थानीय ऑब्जेक्ट से लौटी हुई वस्तु में स्थानांतरित किया जाता है - जो सस्ता है।

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

आरवीओ और एनआरवीओ

आरवीओ का मतलब रिटर्न वैल्यू ऑप्टिमाइजेशन है और यह उन कुछ ऑप्टिमाइज़ेशन में से एक है जो कंपाइलर करते हैं जिनके साइड इफेक्ट हो सकते हैं। चूंकि सी ++ 17, आरवीओ की आवश्यकता है। किसी अनाम वस्तु को वापस करते समय, इसका निर्माण सीधे उस स्थान पर किया जाता है, जहाँ कॉलर लौटाया गया मान प्रदान करता है। न तो कॉपी कंस्ट्रक्टर और न ही मूव कंस्ट्रक्टर को बुलाया जाता है। आरवीओ के बिना, अनाम वस्तु को पहले स्थानीय रूप से निर्मित किया जाएगा, फिर लौटे पते में निर्मित किया जाएगा, फिर स्थानीय अनाम वस्तु को नष्ट कर दिया जाएगा।

उदाहरण जहां आरवीओ आवश्यक है (c ++ 17) या संभावना (c ++ 17 से पहले):

auto function(int a, int b) -> MyStruct {
    // ...
    return MyStruct{a, b};
}

NRVO का अर्थ होता है नामांकित रिटर्न वैल्यू ऑप्टिमाइज़ेशन और यह आरवीओ की तरह ही होता है, सिवाय इसके कि यह किसी नामित ऑब्जेक्ट के लिए किया जाता है जिसे फ़ंक्शन कहते हैं। यह अभी भी मानक (सी ++ 20) द्वारा गारंटी नहीं है, लेकिन कई कंपाइलर अभी भी करते हैं। ध्यान दें कि नामित स्थानीय वस्तुओं के साथ भी, जब वे लौटे तो सबसे खराब स्थिति में हैं।

निष्कर्ष

एकमात्र मामला जहां आपको मूल्य पर वापस नहीं लौटने पर विचार करना चाहिए, जब आपके पास एक नामित, बहुत बड़ा (जैसा कि उसके स्टैक आकार में) ऑब्जेक्ट है। ऐसा इसलिए है क्योंकि NRVO की अभी गारंटी नहीं है (c ++ 20 के रूप में) और यहां तक ​​कि ऑब्जेक्ट को हिलाना भी धीमा होगा। मेरी सिफारिश, और सीपीपी कोर दिशानिर्देशों में सिफारिश हमेशा मूल्य द्वारा वस्तुओं को वापस करने के लिए पसंद करती है (यदि कई रिटर्न मान, संरचना (या टपल) का उपयोग करें), जहां एकमात्र अपवाद तब होता है जब ऑब्जेक्ट को स्थानांतरित करना महंगा होता है। उस स्थिति में, एक नॉन-कास्ट संदर्भ पैरामीटर का उपयोग करें।

यह एक संसाधन को वापस करने के लिए एक अच्छा विचार नहीं है जिसे मैन्युअल रूप से c ++ में फ़ंक्शन से जारी किया जाना है। कभी मत करो। कम से कम एक std :: unique_ptr का उपयोग करें, या एक विध्वंसक के साथ अपना स्वयं का गैर-स्थानीय या स्थानीय ढांचा बनाएं जो अपने संसाधन ( RAII ) को जारी करता है और उसी का एक उदाहरण देता है। यह कदम कंस्ट्रक्टर को परिभाषित करने और असाइनमेंट ऑपरेटर को स्थानांतरित करने के लिए भी एक अच्छा विचार होगा यदि संसाधन का अपना चाल शब्दार्थ नहीं है (और प्रतिलिपि निर्माता / असाइनमेंट को हटा दें)।


दिलचस्प तथ्य। मुझे लगता है कि गोलंग में भी कुछ ऐसा ही है।
मोक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.