2012-02-18 11 views
12

मैं बस सोच रहा था कि संदर्भ आंतरिक रूप से कैसे संग्रहीत किए जाते हैं? मुझे लगा कि उस स्तर से गहराई से समझने से मैं अवधारणा सूचक बनाम संदर्भ को बेहतर तरीके से समझ सकता हूं और निर्णय विकल्प चुन सकता हूं।सी ++ में आंतरिक रूप से संदर्भ कैसे संग्रहीत किए जाते हैं?

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

+6

"मुझे लगा कि उस स्तर को गहराई से समझने से मुझे अवधारणा सूचक बनाम संदर्भ बेहतर समझ जाएगा" मुझे नहीं लगता कि इससे कोई मदद मिलेगी। –

+1

आप इसे आजमा सकते हैं: http://eetimes.com/discussion/programming-pointers/4023307/References-vs-Pointers – Vlad

+0

@ MR.Anubis ..... आपका क्या मतलब है? – howtechstuffworks

उत्तर

11

संदर्भ आंतरिक रूप से केवल उपनाम हैं संकलक उन्हें पॉइंटर्स के समान व्यवहार करते हैं।

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

प्रमुख मतभेद से कुछ हैं:

  • प्वाइंटर NULL हो सकता संदर्भ cannot.There NULL संदर्भ के रूप में कहा जाता है कुछ भी नहीं है, जबकि।
  • const संदर्भ इसके लिए अस्थायी बाध्यता का जीवनकाल बढ़ाता है। पॉइंटर्स के साथ कोई समकक्ष नहीं है।

    • संदर्भ निर्माण के समय प्रारंभ किया जाना चाहिए:

    इसके अलावा, संदर्भ const संकेत (नहीं const के लिए सूचक) के साथ आम में कुछ बातें की है।

  • एक संदर्भ स्थायी रूप से एक ही स्टोरेज स्थान से जुड़ा हुआ है, और बाद में इसे रिबाउंड नहीं किया जा सकता है।

जब आप जानते हैं कि आपके पास कुछ (एक ऑब्जेक्ट) है जिसका संदर्भ है और आप कभी भी किसी अन्य संदर्भ का संदर्भ नहीं लेना चाहते हैं तो संदर्भ अन्य उपयोग पॉइंटर्स का उपयोग करें।

+0

यह पॉइंटर्स के समान नहीं है (हमेशा नहीं)। कंपाइलर को संदर्भों को पूरी तरह से विस्तारित करने की अनुमति है, उदाहरण के लिए 'कक्षा ए {सार्वजनिक: ए(): ए (_ ए) {} int const & a; निजी: int _a; }; ', संदर्भ को समाप्त किया जा सकता है (और इस प्रकार वस्तु के आकार को प्रभावित नहीं कर सकता) जबकि एक सूचक * को elided नहीं किया जा सकता है। –

+0

"जबकि संदर्भ" int और a = * ((int *) 0 नहीं हो सकते हैं; ' – SigTerm

+5

@ सिगटर्म यदि आप सावधानी से लक्ष्य रखते हैं, तो आप अपने आप को पैर में शूट कर सकते हैं। –

14

कोई आवश्यकता नहीं है कि संदर्भ किसी भी तरह से "संग्रहीत" हो। जहां तक ​​भाषा का संबंध है, एक संदर्भ केवल कुछ मौजूदा वस्तु का उपनाम है, और यह सब कुछ है जो किसी भी कंपाइलर को प्रदान करना चाहिए।

यह पूरी तरह से संभव है कि किसी भी अन्य वस्तु के लिए संदर्भ केवल एक छोटा सा हाथ है, या संदर्भ संदर्भ वाले फ़ंक्शन को रेखांकित होने पर कुछ भी स्टोर करने की आवश्यकता नहीं है।

स्थितियों (जैसे जब एक अलग अनुवाद इकाई में एक समारोह बुला), आप व्यावहारिक रूप से एक T & x एक T * const के रूप में लागू करने और के रूप में परोक्ष कि सूचक dereferencing x के हर घटना का इलाज कर सकते हैं जहां संदर्भ प्रकट किया जाने की आवश्यकता है। यहां तक ​​कि उच्च स्तर पर आप T & x = y; और T * const p = &y; (और x और *p के अनुरूप) के बारे में सोच सकते हैं, अनिवार्य रूप से समकक्ष के रूप में, इसलिए संदर्भों को लागू करने का यह एक स्पष्ट तरीका होगा।

लेकिन निश्चित रूप से कोई आवश्यकता नहीं है, और कोई भी कार्यान्वयन जो भी चाहे वह करने के लिए स्वतंत्र है।

+0

मैं देखता हूं, आपके पोस्ट से, मुझे लगता है कि आप कह रहे हैं कि संदर्भ का उपयोग करने के लिए, कोई अतिरिक्त चर आवंटित करने की आवश्यकता नहीं है, आप केवल वेरिएबल्स की तालिका में नाम जोड़ सकते हैं (हालांकि यह मेरी धारणा है)। मुझे नहीं पता, सी ++ अब कैसे काम करता है, लेकिन अगर मैं एक नई ओओपी भाषा लागू करता हूं, तो भी मैं यह सुनिश्चित कर सकता हूं कि स्मृति में कोई अतिरिक्त चर आवंटित नहीं किया गया है, बस याद रखें कि 'ए' का नाम दूसरा नाम है जिसे "a_ref" कहा जाता है ??? ? क्या इसे मैंने ठीक तरह से लिया? – howtechstuffworks

+1

@howtechstuffworks: जब तक संदर्भ केवल स्थानीय या सदस्य स्कोप वेरिएबल्स को संदर्भित करता है, फिर हां। – Puppy

2

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

#include <iostream> 

using namespace std; 

int main() 
{ 
    int i = 10; 
    int *ptrToI = &i; 
    int &refToI = i; 

    cout << "i = " << i << "\n"; 
    cout << "&i = " << &i << "\n"; 

    cout << "ptrToI = " << ptrToI << "\n"; 
    cout << "*ptrToI = " << *ptrToI << "\n"; 
    cout << "&ptrToI = " << &ptrToI << "\n"; 

    cout << "refToNum = " << refToI << "\n"; 
    //cout << "*refToNum = " << *refToI << "\n"; 
    cout << "&refToNum = " << &refToI << "\n"; 

    return 0; 
} 

आउटपुट इस

i = 10 
&i = 0xbf9e52f8 
ptrToI = 0xbf9e52f8 
*ptrToI = 10 
&ptrToI = 0xbf9e52f4 
refToNum = 10 
&refToNum = 0xbf9e52f8 

की तरह है चलो disassembly को देखो (मैं इस। 8,9 के लिए GDB का इस्तेमाल किया और यहां 10 कोड की लाइन नंबर दिए गए हैं)

8   int i = 10; 
0x08048698 <main()+18>: movl $0xa,-0x10(%ebp) 

यहां $0xa 10 (दशमलव) है जिसे हम i पर असाइन कर रहे हैं। -0x10(%ebp) का अर्थ है ebp register -16 (दशमलव) की सामग्री। -0x10(%ebp) स्टैक्स पर i के पते पर इंगित करता है।

9   int *ptrToI = &i; 
0x0804869f <main()+25>: lea -0x10(%ebp),%eax 
0x080486a2 <main()+28>: mov %eax,-0x14(%ebp) 

असाइन ptrToI को i का पता। ptrToI पता -0x14(%ebp) पर स्थित स्टैक पर है, जो ebp - 20 (दशमलव) है।

10   int &refToI = i; 
0x080486a5 <main()+31>: lea -0x10(%ebp),%eax 
0x080486a8 <main()+34>: mov %eax,-0xc(%ebp) 

अब कैच है! लाइन 9 और 10 के डिस्सेप्लर की तुलना करें और आप पर्यवेक्षक होंगे कि -0x14(%ebp) को -0xc(%ebp) द्वारा लाइन संख्या 10 में बदल दिया गया है। -0xc(%ebp) RefToNum का पता है। यह ढेर पर आवंटित किया गया है। लेकिन आप इस पते को कभी भी कोड से प्राप्त नहीं कर पाएंगे क्योंकि आपको पता जानने की आवश्यकता नहीं है।

तो; एक संदर्भ स्मृति पर कब्जा करता है। इस मामले में यह स्टैक मेमोरी है क्योंकि हमने इसे स्थानीय चर के रूप में आवंटित किया है। यह कितनी मेमोरी पर कब्जा करता है? जितना अधिक सूचक होता है।

अब देखते हैं कि हम संदर्भ और पॉइंटर्स तक कैसे पहुंचते हैं। सादगी के लिए मैं विधानसभा का टुकड़ा

16   cout << "*ptrToI = " << *ptrToI << "\n"; 
0x08048746 <main()+192>:  mov -0x14(%ebp),%eax 
0x08048749 <main()+195>:  mov (%eax),%ebx 
19   cout << "refToNum = " << refToI << "\n"; 
0x080487b0 <main()+298>:  mov -0xc(%ebp),%eax 
0x080487b3 <main()+301>:  mov (%eax),%ebx 

अब ऊपर दो पंक्तियों की तुलना का ही हिस्सा दिखाया गया है, आप हड़ताली समानता देखेंगे। -0xc(%ebp)refToI का वास्तविक पता है जो आपके लिए कभी भी सुलभ नहीं है। सरल शब्दों में, यदि आप सामान्य सूचक के रूप में संदर्भ के बारे में सोचते हैं, तो संदर्भ का उपयोग करना संदर्भ द्वारा इंगित पते पर मूल्य लाने जैसा है। इसका मतलब है कोड के नीचे दो पंक्तियों आप एक ही परिणाम

cout << "Value if i = " << *ptrToI << "\n"; 
cout << " Value if i = " << refToI << "\n"; 

दे देंगे अब इस

15   cout << "ptrToI = " << ptrToI << "\n"; 
0x08048713 <main()+141>:  mov -0x14(%ebp),%ebx 
21   cout << "&refToNum = " << &refToI << "\n"; 
0x080487fb <main()+373>:  mov -0xc(%ebp),%eax 

मुझे लगता है कि आप को पहचानना यहाँ क्या हो रहा है में सक्षम हैं की तुलना करें। यदि आप &refToI के लिए पूछते हैं, तो -0xc(%ebp) पता स्थान की सामग्री लौटा दी गई है और -0xc(%ebp) है जहां refToi रहता है और इसकी सामग्री i का पता नहीं है।

एक आखिरी बात, यह पंक्ति क्यों टिप्पणी की गई है?

//cout << "*refToNum = " << *refToI << "\n"; 

क्योंकि *refToI की अनुमति नहीं है और यह आपको एक संकलन समय त्रुटि दे देंगे।