2010-08-07 74 views
32

मैं जावा से सी ++ में जा रहा हूं और भाषा की लचीलापन में थोड़ा उलझन में हूं। एक बिंदु यह है कि वस्तुओं को स्टोर करने के तीन तरीके हैं: एक सूचक, एक संदर्भ और एक स्केलर (यदि मैं इसे सही ढंग से समझता हूं तो ऑब्जेक्ट को स्वयं संग्रहित करता है)।सी ++ में एक सूचक, स्केलर और संदर्भ कब वापस करें?

मैं जहां संभव हो संदर्भों का उपयोग करता हूं, क्योंकि यह जावा जितना संभव हो उतना करीब है। कुछ मामलों में, उदा। व्युत्पन्न विशेषताओं के लिए ही टिककर खेल, यह संभव नहीं है:

MyType &MyClass::getSomeAttribute() { 
    MyType t; 
    return t; 
} 

यह संकलन नहीं करता, क्योंकि t केवल getSomeAttribute() के दायरे के भीतर मौजूद है और अगर मैं इसे करने के लिए एक संदर्भ लौटने के लिए, यह कहीं नहीं बात करने से पहले ग्राहक इसका इस्तेमाल कर सकते हैं ।

  1. वापसी एक सूचक
  2. वापसी एक अदिश

एक सूचक रिटर्निंग इस प्रकार दिखाई देगा:

MyType *MyClass::getSomeAttribute() { 
    MyType *t = new MyType; 
    return t; 
} 

यह

इसलिए मैं दो विकल्पों के साथ छोड़ दिया हूँ काम नहीं है, लेकिन क्लाइंट को NULL के लिए इस पॉइंटर को जांचना होगा वास्तव में, कुछ ऐसा जो संदर्भों के साथ जरूरी नहीं है। एक और समस्या यह है कि कॉलर को यह सुनिश्चित करना होगा कि t को हटा दिया गया है, अगर मैं इससे बच सकता हूं तो मैं इसके साथ सौदा नहीं करूँगा।

विकल्प वस्तु ही (अदिश) लौटने के लिए होगा:

MyType MyClass::getSomeAttribute() { 
    MyType t; 
    return t; 
} 

कि बिल्कुल स्पष्ट है और बस क्या मैं इस मामले में चाहते हैं: यह एक संदर्भ की तरह लगता है और यह खाली नहीं रह सकती। यदि ऑब्जेक्ट क्लाइंट के कोड में दायरे से बाहर है, तो इसे हटा दिया जाता है। बहुत आसान हालांकि, मैं शायद ही कभी ऐसा कर रहा हूं, क्या इसका कोई कारण है? अगर कोई सूचक या संदर्भ के बजाय एक स्केलर लौटाता है तो क्या कोई प्रदर्शन समस्या है?

इस समस्या को संभालने के लिए सबसे आम/सुरुचिपूर्ण दृष्टिकोण क्या है?

+12

"मैं जावा से सी ++ में जा रहा हूं" का अर्थ कुछ भी नहीं है। जावा सी ++ नहीं है। जावा कभी भी सी ++ नहीं होगा। जावा के बारे में सोचते समय प्रोग्रामिंग सी ++ आपको सी ++ को समझने में मदद नहीं करेगा या आपको अच्छे निर्णय लेने में मदद नहीं करेगा। कोई भी भाषा आपको सी ++ को छोड़कर अच्छा सी ++ प्रोग्राम करने में मदद नहीं करेगी, इसलिए आप किसी अन्य भाषा को भूल जाते हैं, क्योंकि वे सी ++ नहीं हैं। यदि आप सी ++ में प्रोग्राम करना चाहते हैं, तो आपको सी ++ सीखना होगा, सी ++ में पूर्व-मौजूदा भाषा को मॉर्फ करने की कोशिश न करें, क्योंकि यह काम नहीं करेगा क्योंकि सी ++ सी ++ है। [क्या मैं एक अच्छी किताब सुझा सकता हूं?] (Http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – GManNickG

+3

एक संदर्भ जावा के करीब नहीं है। जावा के लिए केवल निकटतम भाषा एक सूचक को वापस करने के लिए होगी। लेकिन यह स्मृति प्रबंधन के लिए जिम्मेदार नहीं है। तो जावा के निकटतम सी ++ निर्माण एक साझा सूचक को वापस करना होगा। std :: tr1 :: shared_ptr (या std :: shared_ptr या boost :: shared_ptr (आप किस संस्करण का उपयोग कर रहे हैं इसके आधार पर))। आप नए और अपने दिल की सामग्री को भूल सकते हैं और आम तौर पर ऑब्जेक्ट कचरा सही ढंग से एकत्र किया जाएगा। लेकिन सी ++ जावा नहीं है। आपको मूल्यों का सही तरीके से उपयोग करने का तरीका सीखना होगा। सी ++ में जावा अवधारणाएं न लाएं भाषाएं अलग-अलग हैं। –

+6

@Gman - ठीक है तो सी ++ जावा नहीं है, लेकिन भाषा विनिर्देशों को अनदेखा कर रहा है। जावा में व्यक्त किए गए विचारों का अनुवाद सी ++ में किया जा सकता है। मैं अक्सर कई भाषाओं में प्रोग्राम करता हूं, अक्सर वाक्यविन्यास अलग होता है लेकिन अर्थशास्त्र नहीं। – brumScouse

उत्तर

24

मूल्य से वापसी करें। संकलक प्रतिलिपि को अनुकूलित कर सकता है, इसलिए अंतिम परिणाम वह है जो आप चाहते हैं। एक ऑब्जेक्ट बनाया गया है, और कॉलर पर वापस आ गया है।

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

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

+0

धन्यवाद, इसलिए मूल्य से व्युत्पन्न विशेषता को वापस करने की कोई वास्तविक चेतावनी नहीं है? बढ़िया :) संदर्भ के बजाय सदस्य द्वारा मूल्य को वापस करने के बारे में कैसे मैं वर्तमान में यह कैसे करता हूं? या मूल्य से पैरामीटर गुजर रहा है। क्या यह अक्षम है? – theone

+0

सी ++ में कहीं भी गुफाएं हैं। लेकिन जब तक आप स्पष्ट रूप से ध्यान में रखते हैं, कि आप ऑब्जेक्ट की बजाय * प्रतिलिपि * वापस लौट रहे हैं, और जब तक आपकी प्रति रचनाकार सही ढंग से लिखे गए हों, तो यह ठीक होना चाहिए। – jalf

+0

मूल्य से पैरामीटर पास करने के लिए, यह निर्भर करता है। एक बार फिर, संकलक को कॉपी को खत्म करने की अनुमति है (और यह आमतौर पर इतनी आक्रामक करता है)। इसके अलावा, ऐसे मामले हैं जहां पास-बाय-कॉपी * तेज * हो सकती है (http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/)। लेकिन अक्सर, प्रतिलिपि को अनुकूलित करने के लिए संकलक पर भरोसा करने के बजाय लोग कॉन्स्ट संदर्भ से गुज़रते हैं। – jalf

3

काफी हद तक, जहां भी संभव हो, new द्वारा पॉइंटर्स और गतिशील आवंटन का उपयोग करने से बचें।मूल्यों, संदर्भों और स्वचालित रूप से आवंटित ऑब्जेक्ट्स का उपयोग करें। बेशक आप हमेशा गतिशील आवंटन से बच नहीं सकते हैं, लेकिन यह एक अंतिम उपाय होना चाहिए, पहले नहीं।

0

मूल्य से लौटना सी ++ में प्रचलित एक आम बात है। हालांकि, जब आप किसी ऑब्जेक्ट को पास कर रहे होते हैं, तो आप संदर्भ से गुजरते हैं।

उदाहरण

main() 
    { 

     equity trader; 

     isTraderAllowed(trader); 

     .... 
    } 

    bool isTraderAllowed(const equity& trdobj) 
    { 
      ... // Perform your function routine here. 
    } 

उपरोक्त संदर्भ द्वारा एक वस्तु पास करने का एक सरल उदाहरण है। हकीकत में, आपके पास कक्षा इक्विटी के लिए isTraderAllowed नामक एक विधि होगी, लेकिन मैं आपको संदर्भ द्वारा गुजरने का वास्तविक उपयोग दिखा रहा था।

+0

यह हमेशा मामला नहीं है- कभी-कभी आप मूल्य से गुजरना पसंद कर सकते हैं। – Puppy

2

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

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

व्यक्तिगत रूप से, मैं द्वारा (आमतौर पर स्थिरांक) संदर्भ लौट जब मैं एक सदस्य चर लौट रहा हूँ, और किसी तरह (अक्सर ::std::auto_ptr) की स्मार्ट सूचक वस्तु के कुछ प्रकार वापसी जब मैं गतिशील कुछ आवंटित करने के लिए की जरूरत है। अन्यथा मैं मूल्य से वापस आती हूं।

मुझे भी अक्सर const संदर्भ पैरामीटर हैं, और यह C++ में बहुत आम है। यह पैरामीटर पास करने का एक तरीका है और कह रहा है "फ़ंक्शन को इसे छूने की अनुमति नहीं है"। मूल रूप से केवल पढ़ने के लिए पैरामीटर। यह केवल उन वस्तुओं के लिए उपयोग किया जाना चाहिए जो एक पूर्णांक या सूचक से अधिक जटिल हैं।

मुझे लगता है कि जावा से एक बड़ा परिवर्तन यह है कि const महत्वपूर्ण है और अक्सर उपयोग किया जाता है। इसे समझना और इसे अपने दोस्त बनाना सीखें।

मुझे यह भी लगता है कि नील का जवाब सही है कि जब भी संभव हो गतिशील आवंटन से परहेज करना एक अच्छा विचार है। ऐसा करने के लिए आपको अपने डिज़ाइन को बहुत अधिक नहीं करना चाहिए, लेकिन आपको निश्चित रूप से डिज़ाइन विकल्पों को प्राथमिकता देना चाहिए जिसमें ऐसा नहीं होना चाहिए।

+0

महान सलाह, धन्यवाद। मुझे वास्तव में कॉन्स पसंद है, मैं विश्वास नहीं कर सकता कि मैं इसके बिना कैसे रहता था। फिर भी मुझे अभी भी निर्णय लेने में समस्याएं हैं इसका उपयोग कब करें। उदाहरण के लिए : मेरे पास एक कक्षा है जो अच्छी पुरानी प्रक्रियात्मक ओपनजीएल कॉल को समाहित करती है। यदि कोई विधि ओपनजीएल सामान करता है, तो क्या यह स्थिर है या नहीं? मेरा मतलब है, यह कार्यक्रम में कहीं कुछ राज्य बदलता है। – theone

+0

@theone: सामान्य मुद्दा यह है "क्या यह ऑब्जेक्ट की * तार्किक * स्थिति को बदलता है, यह सदस्य है"। यदि आप मुझे एक कॉन्स ओपनजीएल ऑब्जेक्ट देते हैं, तो मेरे लिए प्रदर्शन करने के लिए कौन सा ऑपरेशन समझ जाएगा? इस बारे में बहुत परेशान मत हो कि क्या यह कहीं कुछ राज्य बदलता है या नहीं। – jalf

+0

@theone, @jalf - मैं जोड़ता हूं कि "तार्किक स्थिति में परिवर्तन" की औपचारिक परिभाषा होनी चाहिए "क्या यह अर्थपूर्ण परिणाम बदलता है (यानी यह कितना समय लेता है, लेकिन यह नहीं करता है) उसी ऑब्जेक्ट के सदस्य फ़ंक्शन को बाद में कॉल करें? "। बेशक, कुछ परिस्थितियों में, 'कॉन्स्ट' की एक कठोर परिभाषा होगी क्योंकि वस्तु का राज्य स्मृति में हो सकता है जो वास्तव में गैर-लिखने योग्य है। – Omnifarious

0

मूल्य या संदर्भ से गुजर के बारे में एक बिंदु:
अनुकूलन को ध्यान में रखते है, अगर इसकी पैरामीटर के रूप में "स्थिरांक डेटा प्रकार objectname" घोषित किया जाता है कि डेटा प्रकार कुछ भी पुरातन हो सकता है एक समारोह संभालने, इनलाइन है, कोई वस्तु प्रति रहेगी शामिल; और यदि इसके पैरामीटर को "कॉन्स्ट डेटा टाइप & ऑब्जेक्टनाम" या "डेटाटाइप & ऑब्जेक्टनाम" के रूप में घोषित किया गया है, तो फिर डेटाटाइप कुछ भी प्राइमेटिव हो सकता है, कोई पता लेने या पॉइंटर शामिल नहीं होगा। पिछले दोनों मामलों में इनपुट तर्क सीधे असेंबली कोड में उपयोग किया जाता है।

एक बिंदु के बारे में संदर्भ:

int adad=5; 
int & reference=adad; 

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

एक बिंदु संदर्भ द्वारा वापसी के बारे में:
इनलाइन कार्य करता है और अनुकूलन के मामले में, संदर्भ से लौटने का पता लेने या सूचक शामिल नहीं होंगे।

+1

सभी बोल्ड वास्तव में आप जो कहने की कोशिश कर रहे हैं उससे अलग हो जाते हैं। –