2009-03-21 16 views
29

बनाम मान लीजिए कि आप एक समारोह है कि एक चर को संशोधित करते हैं।सी ++ कार्य: एम्परसेंड तारांकन

आप इसे इस प्रकार लिख चाहिए: void myfunc(int *a) या इस void myfunc(int &a) की तरह?

पूर्व बलों आप myfunc(&b) साथ समारोह कॉल करने के लिए तो फोन करने वाले कि b संशोधित किया जाएगा बारे में पता है, लेकिन बाद में कम है और myfunc(b) साथ बस कहा जा सकता है। तो उपयोग करने के लिए बेहतर कौन सा है? क्या मुझे कुछ और याद आ रहा है?

+0

वहाँ लेख और इस मुद्दे के बारे विषयों की एक बहुत हैं http://www.google.ru/search?q=pointer+vs+ संदर्भ – abatishchev

उत्तर

36

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

उदाहरण के लिए। Libc फ़ंक्शन time_t time (time_t *result);

यदि result शून्य नहीं है, तो वर्तमान समय संग्रहीत किया जाएगा। लेकिन अगर result शून्य है, तो कोई कार्रवाई नहीं की जाती है।

यदि आप जिस फ़ंक्शन को लिख रहे हैं उसे संदर्भों का उपयोग करने के लिए शून्य का उपयोग करने की आवश्यकता नहीं है (यानी '') शायद कम भ्रमित हो जाएगा - मान लीजिए कि यह प्रोजेक्ट आपके प्रोजेक्ट का उपयोग करता है।

+1

आह, अच्छा बिंदु। अब मुझे ऐसा नहीं लगता इसके बजाय संदर्भ का उपयोग करने के बारे में बुरा। एक सूचक के संदर्भ में फ़ंक्शन को लिखना बहुत आसान है। धन्यवाद :) – mpen

12

जब भी संभव हो मैं संकेत से अधिक संदर्भ का उपयोग। इसका कारण यह है कि एक सूचक से संदर्भ को पेंच करना बहुत मुश्किल है। लोग हमेशा एक सूचक मूल्य पर NULL पास कर सकते हैं लेकिन संदर्भ के लिए इस तरह के बराबर नहीं है।

केवल वास्तविक नकारात्मक पक्ष यह सी में मानकों ++ कॉल साइट दस्तावेज़ीकरण की कमी है वहाँ संदर्भ है। कुछ लोग मानते हैं कि कोड को समझना मुश्किल हो जाता है (और मैं कुछ हद तक सहमत हूं)। मैं आमतौर पर मेरी कोड में निम्नलिखित को परिभाषित करने और नकली कॉल साइट प्रलेखन

#define byref 
... 
someFunc(byref x); 
पाठ्यक्रम लागू नहीं करता है कॉल साइट दस्तावेज की

इस के लिए इसका इस्तेमाल करते हैं। यह सिर्फ इसे दस्तावेज करने का एक बहुत लंगड़ा तरीका प्रदान करता है। मैंने एक टेम्पलेट के साथ कुछ प्रयोग किया जो कॉल साइट दस्तावेज को लागू करता है। वास्तविक उत्पादन कोड के मुकाबले यह मजेदार है।

http://blogs.msdn.com/jaredpar/archive/2008/04/03/reference-values-in-c.aspx

+0

मैं कॉल-साइट के बारे में सहमत हूं जो स्व-दस्तावेज नहीं है। हालांकि, एहसास करें कि संदर्भ पैरामीटर को संशोधित करने वाले कार्यों में हमेशा एक उचित नाम होना चाहिए। उदाहरण के लिए, प्वाइंट.गेटकॉर्ड्स (int & x, int &y); और, mypoint.GetCoords (x, y); – strager

1

पूर्व बलों आप myfunc (& ख) तो फोन करने वाले के साथ समारोह कॉल करने के लिए बारे में पता है कि ख

संशोधित किया जाएगा कभी कभी समारोह स्थिरांक सूचक को स्वीकार कर सकता है और कॉलर को गलत सोच होगी कि बी संशोधित किया जाएगा।

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

मैं बड़ी परियोजना पर मेंटेनर हूँ। और किसी भी मामले में मैं इसे कॉल करने से पहले फ़ंक्शन परिभाषा को देख रहा हूं। जब मैं फ़ंक्शन परिभाषा को देखता हूं, तो मुझे संदर्भ द्वारा, संदर्भ द्वारा, संदर्भ संदर्भ द्वारा या पॉइंटर द्वारा तर्क परिभाषा दिखाई देती है।

लेकिन यह पवित्र युद्ध प्रश्न की तरह लगता है, इस बिंदु पर अपमानजनक लोगों के पास अलग-अलग विचार हैं। जैसे गूगल codding convension बहस में सिफारिश उपयोग संकेत दिए गए जो बदल गया है और अनुमति दी जा सकता है केवल स्थिरांक संदर्भ: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments

सभी मापदंडों संदर्भ द्वारा पारित स्थिरांक लेबल किया जाना चाहिए।

7

मुझे लगता है कि मैं @bb और @JaredPar से असहमत हूं और मैं बाड़ के विपरीत पक्ष में दुबला हूं। अन्य लोगों सी ++ कोड का समर्थन करने के वर्षों के बाद, मुझे अक्सर संदर्भ तर्कों के स्पष्ट दुष्प्रभावों में छिपी हुई समस्याएं मिलती हैं।सी # के साथ, यह स्पष्ट है क्योंकि आपको 'ref'/'out' के साथ तर्कों के प्रकारों को उपसर्ग करना है, लेकिन संदर्भ सी ++ में संभावित रूप से भ्रमित हैं। तो, मुझे पॉइंटर्स पसंद हैं क्योंकि यह वाकई स्पष्ट है कि कुछ वापस आ रहा है। यदि आपको अंक पसंद नहीं हैं, तो सी ++ आपके लिए नहीं है।

+4

मैं आपसे सहमत हूं। संदर्भों के साथ एक गंभीर समस्या यह है कि 'f1 (int), f2 (int &)', जिन्हें कॉल किया जाता है वैसे ही 'एफ 1 (ए), एफ 2 (ए)' लेकिन इसमें एक बड़ा अंतर है। और यह वास्तव में ऐसे कोड को डीबग करने में दर्द हो सकता है। और यह एक आसान गलती है। – Ismael

0

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

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

4

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

Google सी ++ शैली मार्गदर्शिका bans गैर-कॉन्स्ट संदर्भ तर्क।

+0

प्रदान किया गया लिंक पुराना है। क्या कोई इसे अपडेट करेगा? – Jason

+0

इसके अलावा, आप विचार कर सकते हैं कि Google स्टाइल गाइड अच्छे प्रथाओं के लिए सबसे अच्छा संदर्भ नहीं हो सकता है: https://www.linkedin.com/pulse/20140503193653-3046051-why-google-style-guide-for-c-is -ए-डील-ब्रेकर – Jason

+0

प्रोजेक्ट पर निर्भर करता है। –

0

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

एक और बात, यह भी पहले से ही उल्लेख किया है, जब आप कॉल f(a,b) भ्रम हो सकता है अगर फोन करने वाले को पता नहीं है कि f संभावित b

के लिए मूल्य बदल सकता है हालांकि, अभी तक एक और मुद्दा है, जो बल्कि सूक्ष्म है, लेकिन I still ran into it, संदर्भों का अर्थशास्त्र है।

पॉइंटर्स मूल्य से पारित होते हैं, लेकिन संदर्भ नहीं हैं।

जिसका अर्थ है, यदि आप पॉइंटर द्वारा पैरामीटर पास करते हैं, तो आप पॉइंटर बदल सकते हैं और इसे किसी अन्य चीज़ पर इंगित कर सकते हैं।

इस पर विचार करें:

void f1_ptr(type * a) 
{ 
    a = new type(); //no change to passed parameters, you're changing the pointer which was passed by value 
} 

void f2_ptr(type * a) 
{ 
    *a = some_other_value; //now you're changing the value of the parameter that was passed 

    //or, if type is a class or struct: 

    a->some_method_that_modifies_object(); //again, changing the parameter that was passed 
} 

लेकिन, जब संदर्भ द्वारा पारित करने के लिए, आप संदर्भ एक और मूल्य का उल्लेख करने नहीं बदल सकते। एक बार संदर्भ सेट हो जाने पर, इसे बदला नहीं जा सकता है।

void f3_ref(type& a) 
{ 
    a = type(); //the referred variable has also changed 
} 

//.... 

type obj = type(params); 

f3_ref(obj); //obj now changed 

f1_ptr(&obj); //obj doesn't change 

f2_ptr(&obj); //obj now changed 
+0

f2_ptr में, f2_ptr के दायरे में बदलाव। दूसरे शब्दों में, ob2 को संशोधित नहीं किया जाता है जब f2_ptr कहा जाता है (माना जाता है कि (obj) का मूल मान f2_ptr में उपयोग नहीं किया जाता है)। – strager

1

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

myfunc(const_cast< const int& >(a)); 

// Alternatively, this approach may require additional handling 
// in the function, but it's cleaner at call point 
myfunc(boost::cref(a)); 

थोड़ा लाभ के लिए अतिरिक्त कोड का एक बहुत कुछ है यही कारण है कि, हालांकि। जैसा कि केनी ने इंगित किया, सी # ने विपरीत अंत से इसे संबोधित किया (संदर्भ द्वारा विशिष्ट पासिंग की आवश्यकता है), लेकिन यह सी ++ के लिए एक विकल्प नहीं है (उदाहरण के लिए, उदाहरण के लिए, आपने संदर्भ पैरापर को उनके पैरामीटर के रूप में लेने के लिए अपने कार्यों को लिखा है, जैसे boost :: रेफरी (परम)), जैसे:

void myfunc(const boost::reference_wrapper<int>& a) { ... } 

सूचक समस्या फिक्सिंग अधिक समस्याग्रस्त है, हालांकि है ... वहाँ कोई संकलन समय जिस तरह से सुनिश्चित करने के लिए सूचक मान्य है है, तो आप के लिए या तो समय की समस्याओं को चलाने के साथ खत्म सूचक मुद्दों, या रन टाइम चेक, या दोनों। टिटर की प्रकृति है।

वैसे भी, यह मेरी राय है, इसके लायक होने के लिए।

+0

दाएं। लेकिन आप सन्दर्भ में संदर्भ_प्रैपर क्यों लेते हैं, न कि मूल्य से? –

+0

क्योंकि यह एक वर्ग है, और इसे कॉन्स्ट संदर्भ द्वारा पारित करना शायद इसे कॉपी करने से तेज़ है (हालांकि यह कॉपी करने योग्य है)। दोनों काम करेंगे; इस तरह शायद कम ओवरहेड है। – Nick

+0

अच्छी तरह से, संदर्भ_वापर एक सूचक के रूप में बिल्कुल वजन का वजन करता है। मैंने सोचा कि यह बहुत स्पष्ट था। –

1

कुछ नोट करने के लिए, यदि आप एसटीएल फ़ैक्टर का उपयोग कर रहे हैं, तो पैरामीटर कंटेनर मान प्रकार से मेल खाता है तो यह आसान है।

void foo(Bar *); 

void frobnicate(vector<Bar *> vecBars) 
{ 
    for_each(vecBars.begin(), 
      vecBars.end(), 
      ptr_fun(&foo)); 
} 

ऊपर कोड बहुत कठिन है, तो foo बार लेता है &

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