2011-02-16 66 views
7

Possible Duplicate:
FAQ: How to pass objects to functions in C++?
Pointer vs. Referenceसंदर्भ द्वारा कॉल बनाम सूचक तर्क

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

समारोह (संदर्भ द्वारा कॉल)

 
bool calculateSomeValue(vector<string> input, map<string, double>& result) 
{ 
//// bla bla bla 
return true/false; 
} 

समारोह (का उपयोग करते हुए सूचक)

 
bool calculateSomeValue(vector<string> input, map<string, double>* result) 
{ 
//// bla bla bla 
return true/false; 
} 

जो एक सबसे अच्छा है? क्या किसी को इन दोनों विकल्पों के पेशेवरों और विपक्ष का कोई विचार है?

अग्रिम धन्यवाद।

+4

एक संदर्भ के लिए एक सूचक? यह दिलचस्प है ... @ user619237: StackOverflow पर 'पॉइंटर्स बनाम संदर्भों' की खोज करें और आपको कभी भी वांछित उत्तर मिलेगा। :] – Mehrdad

+2

http://stackoverflow.com/questions/114180/pointer-vs-reference – sinek

+2

आपको खोज करने की भी आवश्यकता नहीं है, बस "संबंधित" अनुभाग पर दाईं ओर एक नज़र डालें :) – sinek

उत्तर

11

यह शैली का विषय है।गूगल (Google C++ style guidelines देखें), निम्न प्राथमिकता दी जाएगी:

bool CalculateSomeValue(
    const vector<string>& input, map<string, double>* result); 

इसका कारण यह है एक सूचक का उपयोग कर कॉल स्थल पर एक ampersand का स्पष्ट उपयोग की आवश्यकता है: जैसा कि जिस तरह से करने के लिए विरोध

CalculateSomeValue(input, &result); 

यह एक संदर्भ प्रकार के साथ लागू किया जाएगा:

CalculateSomeValue(input, result); 

मामलों में एक ampersand जहां पैरामीटर संशोधित कर रहे हैं के उपयोग के लिए मजबूर कर रहा करके, यह कॉल स्थल पर स्पष्ट है क्या ज होगा Appen। संदर्भों का उपयोग करते समय, प्रत्येक इनपुट के लिए प्रलेखन को देखना आवश्यक हो जाता है ताकि यह पता चल सके कि इसमें इसके इनपुट पैरामीटर को संशोधित करने की क्षमता है या नहीं।

हालांकि, एक सूचक का उपयोग इसके डाउनसाइड्स भी है। विशेष रूप से, पॉइंटर का उपयोग करने का अर्थ है कि आप कॉलर से नल को संभालने की ज़िम्मेदारी बदलते हैं जहां पॉइंटर को संदर्भित किया जाएगा (यदि परिवर्तक एक सूचक है और न केवल स्थानीय चर के साथ अभिव्यक्ति का पता है)। यही है, जब एक सूचक प्रकार का उपयोग करते हैं, CalculateSomeValue को nullptr (या स्पष्ट रूप से दस्तावेज़ की आवश्यकता है कि उसे कॉलर में इस जांच की आवश्यकता है) की जांच करने की आवश्यकता है, जबकि संदर्भ प्रकार का उपयोग स्वयं-दस्तावेज है और स्पष्ट रूप से इंगित करता है कि एक गैर-शून्य संदर्भ की उम्मीद है।

इस विशेष situtation के लिए, मैं व्यक्तिगत रूप से अत्यधिक एक संकर दृष्टिकोण की सिफारिश:

bool CalculateSomeValue(
    const std::vector<std::string>& input, 
    Output<map<string, double>> result); 

... जहां Output<T> हस्ताक्षर के साथ एक समारोह द्वारा बनाई गई है:

template<typename T> Output<T> WriteTo(T& output_ref); 

... और जहां Output<T> ओवरलोड ऑपरेटर ->, *, आदि। यह मूल रूप से कॉल साइटों को इस तथ्य में स्पष्ट करने के लिए मजबूर करता है कि इनपुट को आवश्यकतानुसार उत्परिवर्तित किया जाएगा:

CalculateSomeValue(input, WriteTo(result)); 

... करने के लिए विरोध के रूप में:

CalculateSomeValue(input, result); 

... जबकि एक साथ संदर्भ की गैर-शून्य अर्थ विज्ञान/वाक्य रचना प्राप्त कर रहा।

+1

एक उल्लेखनीय अपवाद IMHO: कॉन्स रेफरेंस को कॉन्स्ट पॉइंटर्स पर प्राथमिकता दी जाती है। – Mehrdad

+0

हां। ओपी आउटपुट परिणाम के बारे में पूछ रहा था (या कम से कम इस तरह मैंने प्रश्न का अर्थ बताया)। आप मेरे जवाब में नोटिस करेंगे कि मैं इनपुट पैरामीटर के लिए एक कॉन्स्ट संदर्भ का उपयोग करता हूं। –

+0

@ माइकल: ओह, मेरा बुरा - मैं पूरी तरह से वाक्यांश को याद करता हूं "जहां पैरामीटर ** संशोधित ** हैं"। – Mehrdad

0
bool calculateSomeValue(vector<string> input, map<string, double>&* result) 

संदर्भ के लिए सूचक? यह संकलन भी नहीं करेगा। पहला सही है और केवल सही हो सकता है!

struct A {}; 

void f(A & *a) {} 

संकलित देता rrror:

prog.cpp:7: error: cannot declare pointer to ‘struct A&’

Ideone नमूना: http://www.ideone.com/8PJA5

0

आपकी दूसरी कोड नमूने, गलत होने के रूप में आप के लिए एक संदर्भ है, जो shouldn के लिए सूचक स्वीकार करने के लिए कोशिश कर रहे हैं लगता है संकलित नहीं है।

संदर्भ द्वारा पास करना और पॉइंटर पास करना उतना ही कुशल है (अगर मैं गलत हूं तो कोई मुझे सही करता है, लेकिन यह मेरी समझ है कि एक संदर्भ अनिवार्य रूप से स्वचालित रूप से बनाया गया पॉइंटर होता है जिसे तब निर्बाध रूप से संदर्भित किया जाता है), लेकिन संदर्भ से गुजर रहा है इसकी सिफारिश की जाती है क्योंकि यह सुरक्षित है:

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

कुछ स्पष्ट सूचक वाक्यविन्यास पसंद करते हैं जो यह स्पष्ट करता है कि यह किसी ऑब्जेक्ट में एक पॉइंटर है (जैसा कि आपको अव्यवस्था करना चाहिए)।

+0

@ एंड्रयू: मैंने एक बार वाक्य को "आप एक शून्य संदर्भ नहीं दे सकते" और लगभग इसके लिए मौत के लिए पीटा गया, क्योंकि '(int &) (* (int *) NULL) तकनीकी रूप से एक शून्य संदर्भ है। मैंने जो कहा है उससे मैं सहमत हूं, लेकिन सिर्फ आपको चेतावनी देता हूं कि लोग उस वाक्य पर फंस सकते हैं। :) – Mehrdad

+0

@ मेहरदाद: यह एक झूठा रिटॉर्ट है, क्योंकि एक शून्य सूचक का अपरिवर्तनीय अपरिभाषित व्यवहार की ओर जाता है। दूसरे शब्दों में, यदि मेरे पास 'void f (int & i)' फ़ंक्शन है, तो मुझे पता है कि 'मैं हमेशा' int 'का उल्लेख करूंगा। यदि आप कहते हैं, "मैं हो सकता हूं, पास * * ((int *) 0)' "(वैसे, अंतिम कास्ट 'int'' अनावश्यक है), तो आप खुद को पराजित कर चुके हैं क्योंकि आप नहीं मान सकते उस अभिव्यक्ति के बाद किसी भी प्रोग्राम व्यवहार का मूल्यांकन किया जाता है (आप 'f' के अंदर 'i' तक नहीं पहुंच सकते हैं क्योंकि" फ़ंक्शन कॉल करें "व्यर्थ है)। दूसरे शब्दों में, यूबी की वजह से, "संदर्भ" शब्द व्यर्थ है, और इसे शून्य कहा नहीं जा सकता है। – GManNickG

+0

या एक समानता के रूप में, यह मेरे जैसा है "सीट बेल्ट पहनना जीवन बचाता है" और आप जवाब देते हैं "नहीं, अगर आप उन्हें पहनते नहीं हैं!"। यदि आप इसे नहीं पहनते हैं, तो कथन लागू नहीं हो सकता है। – GManNickG

0

सबसे अच्छा समाधान मौजूद नहीं है। यह मामले से मामले में चला जाता है।

उदाहरण के लिए, अगले कुछ स्थितियों में बेहतर हो सकते हैं:

map<string, double> calculateSomeValue(const vector<string> &input) 
{ 
    map<string, double> res; 
// do something with input to form the output 
    return res; 
} 

लेकिन, यदि आप, मानक एल्गोरिदम

+0

रिटर्न वैल्यू आमतौर पर जाने का एक अच्छा तरीका है, लेकिन ओपीएस उदाहरण में रिटर्न टाइप शून्य है और बूल नहीं है, इसलिए आपको अभी भी उस अन्य मूल्य को वापस करने का कोई तरीका होगा। –

+0

@ माइकल ओपीएस उदाहरण में, वापसी मूल्य टाइप बूल के हैं, और मुझे यकीन नहीं है कि मैं आपकी टिप्पणी समझता हूं। क्या आप स्पष्ट कर सकते हो? –

+1

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

0

मैं दूसरा एक संभालने कर रहा हूँ का उपयोग करना पसंद कर सकते हैं बस द्वारा माना जाता है एक संदर्भ के लिए सूचक और बिंदु नहीं।

दोनों के बीच का निर्णय केवल शैली और स्वाद का मामला है। दोनों लाइनों का संकलित परिणाम समान होने की संभावना है।

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

0

संदर्भों का उपयोग करने का एकमात्र समय मानक ऑपरेटरों को लागू करने के लिए लागू होता है।

हालांकि, इसके बाहर, पॉइंटर्स को हमेशा किसी भी आवेदन विधियों के संदर्भों पर प्राथमिकता दी जानी चाहिए।

  • उपयोगकर्ता ऑब्जेक्ट्स अक्सर पॉइंटर्स, स्मार्ट या अन्यथा में संग्रहीत किए जाते हैं। मांग पर वस्तुओं को बनाए जाने पर संदर्भों पर बाधाएं बहुत सख्त होती हैं। यह संदर्भ पैरामीटर को उपयोग करने के लिए असुविधाजनक बनाता है क्योंकि किसी को मूल्य पारित करने के लिए एक बेकार ऑपरेशन करने की आवश्यकता होती है। referenceFunc((*pObj));

  • संदर्भ द्वारा उत्तीर्ण करना अनुबंध प्रतिमान को लागू करने का प्रयास करने के लिए एक सस्ता विकल्प है। कौन सी सी ++ का समर्थन नहीं करता है।

  • उस पास-बाय-रेफरेंस पर सभी (* कुछ पीआरटी) संचालन का अर्थ यह होगा कि आप किसी भी तरह से डीबग करने के लिए शून्य पॉइंटर प्राप्त करने जा रहे हैं, बस अधिक स्पष्ट नहीं है क्योंकि शून्य सूचक एक सूचक की तरह नहीं दिखेंगे।

  • रखरखाव समस्या को नज़रअंदाज़ करें जब प्रोग्रामर सरल परीक्षा द्वारा नहीं बता सकते हैं कि फ़ंक्शन के पैरामीटर बदल सकते हैं।

1

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

आप मान सकते हैं कि एक संदर्भ शून्य नहीं है, लेकिन आपको पॉइंटर्स के लिए यह नहीं मानना ​​चाहिए। उस स्थिति में, आपको यह सुनिश्चित करने के लिए पूर्व शर्त मचान/चेक पेश करना होगा कि किसी को अपस्ट्रीम विश्वास नहीं था कि तर्क वैकल्पिक था - यदि आप रक्षात्मक हैं।

व्यक्तिगत रूप से, मैं संदर्भ द्वारा पास करना पसंद करता हूं, और वर्णनात्मक विधि/फ़ंक्शन/चर नामों का उपयोग करना पसंद करता हूं (यदि आप केवल लेबल का विस्तार करते हैं, तो लोगों को दस्तावेज़ों पर अधिक बार जाना होगा)। यह कार्यक्रम के इरादे को स्पष्ट रखता है, और अतिरिक्त लिखित चेक से बचाता है। get* या update*calculate* से अधिक स्पष्ट हो सकता है।

संदर्भों का उपयोग कर, सुसंगत रूप से परिभाषित किया गया है, और सरल प्रोग्राम तैयार करता है क्योंकि आप मिश्रित चर/तर्क प्रकारों से निपट नहीं रहे हैं।

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

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