2009-03-06 16 views
52

ये वही कर रहे हैं:अंतर?

int foo(bar* p) { 
    return p->someInt(); 
} 

और

int foo(bar& r) { 
    return r.someInt(); 
} 

नल पॉइंटर संभावित पर ध्यान न दें। इन दोनों कार्यों कार्यात्मक कोई फर्क नहीं पड़ता समान हैं, तो someInt() आभासी है या वे एक bar या bar का एक उपवर्ग पारित कर रहे हैं तो क्या होगा?

इस टुकड़ा कुछ भी करता है:

bar& ref = *ptr_to_bar; 

उत्तर

58

सी ++ संदर्भ जानबूझकर मानक में निर्दिष्ट नहीं कर रहे हैं संकेत का उपयोग कर लागू किया जाना। एक संदर्भ एक सूचक के रूप में एक संकेतक के लिए "synonym" की तरह अधिक है। यह अर्थशास्त्र संकलक के लिए कुछ संभावित अनुकूलन खोलता है जब यह महसूस करना संभव है कि कुछ स्थितियों में एक सूचक अधिक ओवरकिल होगा।

कुछ और मतभेद:

  • आप एक संदर्भ के लिए शून्य नहीं सौंप सकते। यह एक महत्वपूर्ण अंतर और मुख्य कारण आप एक दूसरे के ऊपर प्राथमिकता देना चाहेंगे है।
  • जब आप एक सूचक का पता लेते हैं, आप सूचक चर का पता मिलता है। जब आप किसी संदर्भ के पता लेते हैं, आप के लिए भेजा चर होने का पता मिलता है।
  • आप एक संदर्भ पुन: असाइन नहीं कर सकते हैं। एक बार इसे शुरू करने के बाद यह एक ही वस्तु को अपने पूरे जीवन के लिए इंगित करता है।
+5

आप वास्तव में अगर आप इसे प्रकार का एक सूचक को डाल सकते हैं और एक संदर्भ के लिए शून्य असाइन कर सकते हैं तो बिंदु भिन्नता उदा int और ref = * (int *) NULL; और यदि आप इसे एक संघ के भीतर रखते हैं और संघ में संबंधित मान को बदलते हैं तो आप संदर्भ को फिर से सौंप सकते हैं। –

+0

और मुझे यह जोड़ना चाहिए कि इन्हें कभी नहीं किया जाना चाहिए क्योंकि जब कोई फ़ंक्शन संदर्भ के लिए पूछता है, तो यह कभी भी पूर्ण की अपेक्षा नहीं करता है, और हालांकि अधिकांश संदर्भ मूल रूप से पॉइंटर्स के समान ही लागू होते हैं, यह सभी परिदृश्यों में मामला नहीं हो सकता है/प्लेटफार्मों। –

+0

यदि आप एक संघ के संबंधित मूल्य को आवंटित कर रहे हैं तो आप वास्तव में संदर्भ के लिए असाइन नहीं कर रहे हैं? – shoosh

3

मैं सी ++ एक लंबे समय में उपयोग नहीं किया है, तो मैं भी वास्तव में अपने सवाल का जवाब देने (खेद) प्रयास करने के लिए नहीं जा रहा हूँ; हालांकि, एरिक लिपर्ट ने सिर्फ excellent article को पॉइंटर्स/संदर्भों के बारे में पोस्ट किया जो मुझे लगा कि मैं आपको इंगित करूंगा।

4

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

यह भी semantical अंतर देखने के लिए महत्वपूर्ण है:

  • एक संदर्भ का उपयोग करें जब आप वास्तव में वस्तु सामान्य से होकर गुजरेगा - लेकिन यह नहीं बल्कि ऑब्जेक्ट के संदर्भ पारित करने के लिए इतनी बड़ी है कि यह अधिक समझ में आता है है एक प्रतिलिपि बनाने से (यदि आप उस ऑब्जेक्ट को संशोधित नहीं कर रहे हैं)।
  • जब आप ऑब्जेक्ट के बजाए मेमोरी एड्रेस से निपटना चाहते हैं तो पॉइंटर का उपयोग करें।
1

फ़ंक्शंस स्पष्ट रूप से "वही नहीं" हैं, लेकिन आभासी व्यवहार के संबंध में वे समान व्यवहार करेंगे। स्लाइसिंग के संबंध में, यह तब होता है जब आप अंतराल से निपटते हैं, संदर्भ या पॉइंटर्स नहीं।

+0

असल में, वे शायद समान मशीन कोड उत्पन्न करते हैं, इसलिए उस अर्थ में वे वही हैं। – jmucchiello

13

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

और नहीं, आपकी लाइन टुकड़ा नहीं है। यह सिर्फ पॉइंटर द्वारा इंगित ऑब्जेक्ट पर संदर्भ को बाध्यकारी है।

कारण है कि आप एक दूसरे के ऊपर का उपयोग करना चाहते हैं उस पर कुछ सवाल:

इसके बजाय अंतर के साथ अपने आप को आने की कोशिश कर के, मैं यदि आप जानना चाहते हैं तो उनको आपको प्रतिनिधि दें।

3

जैसा कि हर किसी ने उल्लेख किया है, कार्यान्वयन संदर्भ और पॉइंटर्स काफी हद तक समान हैं। वहाँ कुछ मामूली चेतावनियां हैं:

  • आप एक संदर्भ (shoosh इस उल्लेख) को शून्य असाइन नहीं कर सकते: के बाद से कोई "अनिर्धारित" या "अवैध" संदर्भ मूल्य कि महत्वपूर्ण है।

  • आप एक स्थिरांक संदर्भ, के रूप में एक अस्थायी चर पारित कर सकते हैं, लेकिन यह एक अस्थायी करने के लिए एक सूचक पारित करने के लिए कानूनी नहीं है।

उदाहरण के लिए, यह ठीक है:

class Thingy; // assume a constructor Thingy(int,int) 
void foo(const Thingy &a) 
{ 
    a.DoSomething(); 
} 

void bar() 
{ 
    foo(Thingy(1,2)); 
} 

लेकिन सबसे compilers के बारे में

void foo2(Thingy * a); 

void bar2() 
{ 
    foo(&Thingy(1,2)); 
} 
  • एक चर के पते ले रहा है एक सूचक प्राप्त करने के लिए संकलक बलों शिकायत इसे स्मृति में सहेजें। स्थानीय चर के संदर्भ को असाइन करना सिर्फ समानार्थी बनाता है; कुछ मामलों में यह संकलक को डेटा पर डेटा रखने की अनुमति दे सकता है और load-hit-store से बच सकता है। हालांकि, यह केवल स्थानीय चर पर लागू होता है - एक बार संदर्भ द्वारा पैरामीटर के रूप में कुछ पारित होने के बाद, इसे स्टैक करने के लिए सहेजने से कोई बचा नहीं जाता है।

 

void foo() 
{ 
    int a = 5; 
    // this may be slightly more efficient 
    int &b = a; 
    printf("%d", ++b); 
    // than this 
    int *c = &a; 
    printf("%d", ++(*c)); 
} 
  • इसी तरह, __restrict keyword संदर्भ, केवल संकेत करने के लिए लागू नहीं किया जा सकता।

  • आप संदर्भ के साथ पॉइंटर अंकगणित नहीं कर सकते हैं, इसलिए यदि आपके पास एक सरणी में पॉइंटर है तो सरणी में अगला तत्व पी + 1 के माध्यम से हो सकता है, एक संदर्भ केवल एक चीज पर ही इंगित करता है पूरा जीवन।

4

सुनिश्चित नहीं है कि किसी ने स्लाइसिंग के बारे में नीचे दिए गए आपके दूसरे प्रश्न का उत्तर दिया है ... कोई भी टुकड़ा नहीं करेगा।

स्लाइसिंग तब होती है जब एक व्युत्पन्न वस्तु को बेस क्लास ऑब्जेक्ट में (कॉपी किया गया) दिया जाता है - व्युत्पन्न वर्ग की विशेषज्ञता "कटा हुआ" होती है।ध्यान दें कि मैंने कहा है कि ऑब्जेक्ट कॉपी किया गया है, हम प्रतिबिंबित/निर्दिष्ट किए गए पॉइंटर्स के बारे में बात नहीं कर रहे हैं, लेकिन ऑब्जेक्ट्स स्वयं।

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

11

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

पूर्व के लिए:

 int j = 10; 
     int &i = j; 
     int l = 20; 
     i = l; // Now value of j = 20 

     int *k = &j; 
     k = &l; // Value of j is still 10