2013-09-22 7 views
8

तो, मैं हमेशा सी ++ पॉइंटर्स बनाम पर थोड़ा अस्पष्ट रहा हूं ... जो भी दूसरे को बुलाया जाता है। की तरह,स्टैक वैरिएबल लौट रहे हैं?

Object* pointer = new Object(); 

बनाम

Object notpointer(); 

मुझे पता है कि संकेत शायद दूसरा एक में शामिल हैं, लेकिन मूल रूप से यह एक नहीं के सूचक है। (क्या यह वास्तव में कहा जाता है?)

इसके अलावा, मैं, है ना मानना ​​है कि पहले एक के लिए, आप कुछ बिंदु पर

delete pointer; 

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

हालांकि, जब आप किसी फ़ंक्शन से कुछ (मूल नहीं) लौट रहे हैं तो क्या होगा?

एक अच्छा उदाहरण Should I return std::strings? में लिखा है:

std::string linux_settings_provider::get_home_folder() { 
    return std::string(getenv("HOME")); 
} 

मैं पहले क्या लिखा है, स्ट्रिंग ढेर पर आवंटित किया जाता है, और मुक्त कर दिया जाना चाहिए द्वारा जब समारोह रिटर्न, है ना? फिर भी किसी ने इसके बारे में कुछ नहीं कहा, इसलिए मुझे लगता है कि यह ठीक काम करता है। क्यूं कर?

सामान्य तौर पर,

return new std::string("pointer"); 

और

return std::string("not-pointer"); 

के बीच अंतर क्या है?

साथ ही, दोनों कामों को मानते हुए, दोनों के पेशेवरों और विपक्ष क्या हैं?

+1

दूसरा एक कार्य है। – chris

+0

आप यहां कई अवधारणाओं को मिश्रित कर रहे हैं। एक सूचक केवल एक चर है जो स्मृति पता रख सकता है। 'नया std :: string' स्मृति आवंटन और ऑब्जेक्ट निर्माण कर रहा है। उन दो चीजों को एक साथ उपयोग करने की आवश्यकता नहीं है। आधुनिक सी ++ में, आप आमतौर पर ऐसा नहीं करते हैं। – greatwolf

+0

स्ट्रिंग पर स्ट्रिंग आवंटित की जाती है। यह ** ** ** मुक्त नहीं है; यह नष्ट हो गया है लेकिन संकलक इसे नष्ट करने से पहले इसे कॉपी करता है। –

उत्तर

11

जब आप पॉइंटर द्वारा लौटते हैं, तो आपको एक गतिशील रूप से आवंटित ऑब्जेक्ट को जिस तरह से दिखाया जाता है उसे वापस करने की आवश्यकता होती है (यानी एक स्टैक ऑब्जेक्ट परिणामों में पॉइंटर को अपरिभाषित व्यवहार में बाद में संदर्भित किया जाता है)। यह स्मृति रिसाव के लिए एक संभावित बनाता है, क्योंकि, जैसा कि आपने ध्यान दिया है, उस ऑब्जेक्ट को स्पष्ट रूप से हटाया जाना चाहिए।

मूल्य द्वारा रिटर्निंग, दूसरे हाथ पर (दूसरा टुकड़ा यानी) वस्तु को कॉपी में परिणाम है कि आप ढेर वस्तु से लौटने कि आप उद्देश्य यह है कि वापसी मान प्राप्त करता है में वापसी:

std::string res = get_home_folder(); // std::string gets copied into res 

संकलनकर्ता return value optimization के माध्यम से कॉपी करने से बचने के लिए इसे अनुकूलित कर सकते हैं।

+0

@ बेंजामिन लिंडली आप सही हैं, जो सही नहीं दिख रहे हैं। धन्यवाद! – dasblinkenlight

+0

धन्यवाद! तो, आप एक वेरिएबल को क्या कहते हैं जो सूचक नहीं है? – Erhannis

+0

@ एरहनीस सही, पहले स्निपेट में 'res' एक सूचक नहीं है। – dasblinkenlight

1

मुझे लगता है कि आप वास्तव में Object notpointer(); लिखना नहीं चाहते थे क्योंकि यह वास्तव में notpointer नामक एक फ़ंक्शन घोषित करता है जो Object लौटाता है। यदि आपका मतलब Object notpointer; है तो प्रश्नों की संस्थाएं मान पर कॉल करती हैं। मान वास्तव में, ढेर पर आवंटित होते हैं, या जब ऑब्जेक्ट में एम्बेडेड ऑब्जेक्ट्स के सदस्य होते हैं।

कुछ भी लौटने पर, वापस लौटाई जाने वाली इकाई की प्रतिलिपि बनाई जाती है या उस स्थान पर स्थानांतरित की जाती है जहां वास्तविक वापसी मूल्य की अपेक्षा की जाती है। एक बार वापसी मूल्य का निर्माण हो जाने के बाद, स्थानीय वस्तु, यानी, ढेर पर, गुंजाइश से बाहर निकलते हैं और नष्ट हो जाते हैं।यह देखते हुए कि स्थानीय वस्तुएं वैसे भी दूर जा रही हैं, संकलक को प्रतिलिपि बनाने और ऑब्जेक्ट को सही स्थान पर तुरंत बनाने की अनुमति है, भले ही कॉपी कन्स्ट्रक्टर और/या विनाशक के दुष्प्रभाव हों।

अंतर अपने दो रिटर्न बयानों के बीच जब new std::string("pointer") का उपयोग कर आप एक वस्तु ढेर पर आवंटित हो जाते हैं और आप वस्तु के लिए एक सूचक लौट

  1. है। ऐसा नहीं है कि सूचक लीक करने के लिए बहुत आसान है और आप एक उपयुक्त वस्तु में इसे तुरंत डाल करने के लिए, उदाहरण के लिए एक std::unique_ptr<std::string> बेहतर होगा:

    return std::unique_ptr<std::string>(new std::string("pointer")); 
    

    इस तरह, सूचक लीक नहीं किया जाएगा। बेशक, आप रिटर्न प्रकार को std::unique_ptr<std::string> के बजाय std::string* में बदल देंगे। ध्यान दें, कि ढेर आवंटन आम तौर पर काफी महंगा होते हैं।

  2. std::string("value") का उपयोग करते समय आप बस एक स्थानीय चर लौटाते हैं। एक अच्छा मौका है कि प्रतिलिपि बनाई जाएगी और वापसी मूल्य उस स्थान पर तुरंत बनाया जाएगा जहां इसे जाना चाहिए। किसी भी संसाधन की देखभाल करने की कोई आवश्यकता नहीं है क्योंकि इसमें शामिल सभी वस्तुओं को स्वचालित रूप से नष्ट कर दिया जाएगा। कोई स्पष्ट ढेर आवंटन नहीं है और आवंटन ढेर बहुत तेज़ हैं।

बेशक, दिए गए उदाहरण में std::string वास्तव में दोनों मामलों में आंतरिक प्रतिनिधित्व आवंटित करने की आवश्यकता है। यदि सूचक वापस लौटाया जाता है, तो यह गारंटी दी जाती है कि कोई अतिरिक्त आंतरिक आवंटन नहीं है। दूसरी ओर, जब std::string मान वापस लौटाते हैं और वास्तव में इसकी प्रतिलिपि बनाने की आवश्यकता होती है, तो आंतरिक स्मृति को प्रतिलिपि के लिए आवंटित करने की आवश्यकता हो सकती है। यही है, जब बड़ी वस्तुओं को वापस लौटते हैं, संभवतः बहुत सारे स्मृति आवंटन की आवश्यकता होती है, तो मूल्य लौटने का दृष्टिकोण जोखिम को चलाता है जिसे इसकी प्रतिलिपि बनाने की आवश्यकता होती है। वर्तमान सी ++ के साथ ऑब्जेक्ट्स सबसे बुरे मामले में चले गए हैं, यानी, ऑब्जेक्ट्स को कॉपी करने के बारे में चिंता करने की कोई चिंता नहीं है क्योंकि सी ++ 03 में था।

+0

क्षमा करें; मुझे लगता है कि 'std :: string text ("notpointer") के बाद से '' std :: string' के लिए 1-पैरामीटर कन्स्ट्रक्टर कहा जाता है,' ऑब्जेक्ट obj(); 'ऑब्जेक्ट' के लिए 0-पैरामीटर कन्स्ट्रक्टर कहा जाता है । जाहिरा तौर पर नहीं। – Erhannis

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